blob: 89da0c850681872a45d1f771c444159df4526a3e [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 *
151 * Returns -2 or +2 based on the order
152 */
153static
154int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
155#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
156 static int xmlXPathCmpNodesExt(xmlNodePtr, xmlNodePtr);
157 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
158 {
159 int res = xmlXPathCmpNodesExt(x, y);
160 return res == -2 ? res : -res;
161 }
162#else
163 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
164 {
165 int res = xmlXPathCmpNodes(x, y);
166 return res == -2 ? res : -res;
167 }
168#endif
169#define SORT_CMP(x, y) (wrap_cmp(x, y))
170#include "timsort.h"
171#endif /* WITH_TIM_SORT */
172
William M. Brack21e4ef22005-01-02 09:53:13 +0000173#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000174
175/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000176 * *
177 * Floating point stuff *
178 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000179 ************************************************************************/
180
Daniel Veillardc0631a62001-09-20 13:56:06 +0000181#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +0000182#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +0000183#endif
Daniel Veillardcda96922001-08-21 10:56:31 +0000184#include "trionan.c"
185
Owen Taylor3473f882001-02-23 17:55:21 +0000186/*
Owen Taylor3473f882001-02-23 17:55:21 +0000187 * The lack of portability of this section of the libc is annoying !
188 */
189double xmlXPathNAN = 0;
190double xmlXPathPINF = 1;
191double xmlXPathNINF = -1;
Daniel Veillard24505b02005-07-28 23:49:35 +0000192static double xmlXPathNZERO = 0; /* not exported from headers */
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000193static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000194
Owen Taylor3473f882001-02-23 17:55:21 +0000195/**
196 * xmlXPathInit:
197 *
198 * Initialize the XPath environment
199 */
200void
201xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000202 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +0000203
Bjorn Reese45029602001-08-21 09:23:53 +0000204 xmlXPathPINF = trio_pinf();
205 xmlXPathNINF = trio_ninf();
206 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000207 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +0000208
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000209 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000210}
211
Daniel Veillardcda96922001-08-21 10:56:31 +0000212/**
213 * xmlXPathIsNaN:
214 * @val: a double value
215 *
216 * Provides a portable isnan() function to detect whether a double
217 * is a NotaNumber. Based on trio code
218 * http://sourceforge.net/projects/ctrio/
Daniel Veillard45490ae2008-07-29 09:13:19 +0000219 *
Daniel Veillardcda96922001-08-21 10:56:31 +0000220 * Returns 1 if the value is a NaN, 0 otherwise
221 */
222int
223xmlXPathIsNaN(double val) {
224 return(trio_isnan(val));
225}
226
227/**
228 * xmlXPathIsInf:
229 * @val: a double value
230 *
231 * Provides a portable isinf() function to detect whether a double
232 * is a +Infinite or -Infinite. Based on trio code
233 * http://sourceforge.net/projects/ctrio/
Daniel Veillard45490ae2008-07-29 09:13:19 +0000234 *
Daniel Veillardcda96922001-08-21 10:56:31 +0000235 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
236 */
237int
238xmlXPathIsInf(double val) {
239 return(trio_isinf(val));
240}
241
Daniel Veillard4432df22003-09-28 18:58:27 +0000242#endif /* SCHEMAS or XPATH */
243#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000244/**
245 * xmlXPathGetSign:
246 * @val: a double value
247 *
248 * Provides a portable function to detect the sign of a double
249 * Modified from trio code
250 * http://sourceforge.net/projects/ctrio/
Daniel Veillard45490ae2008-07-29 09:13:19 +0000251 *
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000252 * Returns 1 if the value is Negative, 0 if positive
253 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000254static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000255xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000256 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000257}
258
259
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000260/*
261 * TODO: when compatibility allows remove all "fake node libxslt" strings
262 * the test should just be name[0] = ' '
263 */
Daniel Veillard074f37e2008-09-01 13:38:22 +0000264#ifdef DEBUG_XPATH_EXPRESSION
265#define DEBUG_STEP
266#define DEBUG_EXPR
267#define DEBUG_EVAL_COUNTS
268#endif
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000269
270static xmlNs xmlXPathXMLNamespaceStruct = {
271 NULL,
272 XML_NAMESPACE_DECL,
273 XML_XML_NAMESPACE,
274 BAD_CAST "xml",
William M. Brackee0b9822007-03-07 08:15:01 +0000275 NULL,
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000276 NULL
277};
278static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
279#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard45490ae2008-07-29 09:13:19 +0000280/*
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000281 * Optimizer is disabled only when threaded apps are detected while
282 * the library ain't compiled for thread safety.
283 */
284static int xmlXPathDisableOptimizer = 0;
285#endif
286
Owen Taylor3473f882001-02-23 17:55:21 +0000287/************************************************************************
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000288 * *
289 * Error handling routines *
290 * *
291 ************************************************************************/
292
Daniel Veillard24505b02005-07-28 23:49:35 +0000293/**
294 * XP_ERRORNULL:
295 * @X: the error code
296 *
297 * Macro to raise an XPath error and return NULL.
298 */
299#define XP_ERRORNULL(X) \
300 { xmlXPathErr(ctxt, X); return(NULL); }
301
William M. Brack08171912003-12-29 02:52:11 +0000302/*
303 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
304 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000305static const char *xmlXPathErrorMessages[] = {
306 "Ok\n",
307 "Number encoding\n",
308 "Unfinished literal\n",
309 "Start of literal\n",
310 "Expected $ for variable reference\n",
311 "Undefined variable\n",
312 "Invalid predicate\n",
313 "Invalid expression\n",
314 "Missing closing curly brace\n",
315 "Unregistered function\n",
316 "Invalid operand\n",
317 "Invalid type\n",
318 "Invalid number of arguments\n",
319 "Invalid context size\n",
320 "Invalid context position\n",
321 "Memory allocation error\n",
322 "Syntax error\n",
323 "Resource error\n",
324 "Sub resource error\n",
325 "Undefined namespace prefix\n",
326 "Encoding error\n",
Daniel Veillard57b25162004-11-06 14:50:18 +0000327 "Char out of XML range\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000328 "Invalid or incomplete context\n",
Daniel Veillardf5048b32011-08-18 17:10:13 +0800329 "Stack usage errror\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000330 "?? Unknown error ??\n" /* Must be last in the list! */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000331};
William M. Brackcd65bc92005-01-06 09:39:18 +0000332#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
333 sizeof(xmlXPathErrorMessages[0])) - 1)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000334/**
335 * xmlXPathErrMemory:
336 * @ctxt: an XPath context
337 * @extra: extra informations
338 *
339 * Handle a redefinition of attribute error
340 */
341static void
342xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
343{
344 if (ctxt != NULL) {
345 if (extra) {
346 xmlChar buf[200];
347
348 xmlStrPrintf(buf, 200,
349 BAD_CAST "Memory allocation failed : %s\n",
350 extra);
351 ctxt->lastError.message = (char *) xmlStrdup(buf);
352 } else {
353 ctxt->lastError.message = (char *)
354 xmlStrdup(BAD_CAST "Memory allocation failed\n");
355 }
356 ctxt->lastError.domain = XML_FROM_XPATH;
357 ctxt->lastError.code = XML_ERR_NO_MEMORY;
358 if (ctxt->error != NULL)
359 ctxt->error(ctxt->userData, &ctxt->lastError);
360 } else {
361 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000362 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000363 NULL, NULL, XML_FROM_XPATH,
364 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
365 extra, NULL, NULL, 0, 0,
366 "Memory allocation failed : %s\n", extra);
367 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000368 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000369 NULL, NULL, XML_FROM_XPATH,
370 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
371 NULL, NULL, NULL, 0, 0,
372 "Memory allocation failed\n");
373 }
374}
375
376/**
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000377 * xmlXPathPErrMemory:
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000378 * @ctxt: an XPath parser context
379 * @extra: extra informations
380 *
381 * Handle a redefinition of attribute error
382 */
383static void
384xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
385{
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000386 if (ctxt == NULL)
387 xmlXPathErrMemory(NULL, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000388 else {
389 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000390 xmlXPathErrMemory(ctxt->context, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000391 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000392}
393
394/**
395 * xmlXPathErr:
396 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000397 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000398 *
William M. Brackcd65bc92005-01-06 09:39:18 +0000399 * Handle an XPath error
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000400 */
401void
402xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
403{
William M. Brackcd65bc92005-01-06 09:39:18 +0000404 if ((error < 0) || (error > MAXERRNO))
405 error = MAXERRNO;
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000406 if (ctxt == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000407 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000408 NULL, NULL, XML_FROM_XPATH,
409 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
410 XML_ERR_ERROR, NULL, 0,
411 NULL, NULL, NULL, 0, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200412 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000413 return;
414 }
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000415 ctxt->error = error;
416 if (ctxt->context == NULL) {
417 __xmlRaiseError(NULL, NULL, NULL,
418 NULL, NULL, XML_FROM_XPATH,
419 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
420 XML_ERR_ERROR, NULL, 0,
421 (const char *) ctxt->base, NULL, NULL,
422 ctxt->cur - ctxt->base, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200423 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000424 return;
425 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +0000426
427 /* cleanup current last error */
Daniel Veillard45490ae2008-07-29 09:13:19 +0000428 xmlResetError(&ctxt->context->lastError);
Aleksey Sanin1b2be102006-05-31 20:53:43 +0000429
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000430 ctxt->context->lastError.domain = XML_FROM_XPATH;
431 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
432 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000433 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000434 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
435 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
436 ctxt->context->lastError.node = ctxt->context->debugNode;
437 if (ctxt->context->error != NULL) {
438 ctxt->context->error(ctxt->context->userData,
439 &ctxt->context->lastError);
440 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000441 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000442 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
443 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
444 XML_ERR_ERROR, NULL, 0,
445 (const char *) ctxt->base, NULL, NULL,
446 ctxt->cur - ctxt->base, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200447 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000448 }
449
450}
451
452/**
453 * xmlXPatherror:
454 * @ctxt: the XPath Parser context
455 * @file: the file name
456 * @line: the line number
457 * @no: the error number
458 *
459 * Formats an error message.
460 */
461void
462xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
463 int line ATTRIBUTE_UNUSED, int no) {
464 xmlXPathErr(ctxt, no);
465}
466
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000467/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000468 * *
469 * Utilities *
470 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000471 ************************************************************************/
472
473/**
474 * xsltPointerList:
475 *
476 * Pointer-list for various purposes.
477 */
478typedef struct _xmlPointerList xmlPointerList;
479typedef xmlPointerList *xmlPointerListPtr;
480struct _xmlPointerList {
481 void **items;
482 int number;
483 int size;
484};
485/*
486* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
487* and here, we should make the functions public.
488*/
489static int
Daniel Veillard45490ae2008-07-29 09:13:19 +0000490xmlPointerListAddSize(xmlPointerListPtr list,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000491 void *item,
492 int initialSize)
493{
494 if (list->items == NULL) {
495 if (initialSize <= 0)
496 initialSize = 1;
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800497 list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000498 if (list->items == NULL) {
499 xmlXPathErrMemory(NULL,
500 "xmlPointerListCreate: allocating item\n");
501 return(-1);
502 }
503 list->number = 0;
504 list->size = initialSize;
505 } else if (list->size <= list->number) {
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800506 if (list->size > 50000000) {
507 xmlXPathErrMemory(NULL,
508 "xmlPointerListAddSize: re-allocating item\n");
509 return(-1);
510 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000511 list->size *= 2;
512 list->items = (void **) xmlRealloc(list->items,
513 list->size * sizeof(void *));
514 if (list->items == NULL) {
515 xmlXPathErrMemory(NULL,
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800516 "xmlPointerListAddSize: re-allocating item\n");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000517 list->size = 0;
518 return(-1);
519 }
520 }
521 list->items[list->number++] = item;
522 return(0);
523}
524
525/**
526 * xsltPointerListCreate:
527 *
528 * Creates an xsltPointerList structure.
529 *
530 * Returns a xsltPointerList structure or NULL in case of an error.
531 */
532static xmlPointerListPtr
533xmlPointerListCreate(int initialSize)
534{
535 xmlPointerListPtr ret;
536
537 ret = xmlMalloc(sizeof(xmlPointerList));
538 if (ret == NULL) {
539 xmlXPathErrMemory(NULL,
540 "xmlPointerListCreate: allocating item\n");
541 return (NULL);
542 }
543 memset(ret, 0, sizeof(xmlPointerList));
544 if (initialSize > 0) {
545 xmlPointerListAddSize(ret, NULL, initialSize);
546 ret->number = 0;
547 }
548 return (ret);
549}
550
551/**
552 * xsltPointerListFree:
553 *
554 * Frees the xsltPointerList structure. This does not free
555 * the content of the list.
556 */
557static void
558xmlPointerListFree(xmlPointerListPtr list)
559{
560 if (list == NULL)
561 return;
562 if (list->items != NULL)
563 xmlFree(list->items);
564 xmlFree(list);
565}
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000566
567/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000568 * *
569 * Parser Types *
570 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000571 ************************************************************************/
572
573/*
574 * Types are private:
575 */
576
577typedef enum {
578 XPATH_OP_END=0,
579 XPATH_OP_AND,
580 XPATH_OP_OR,
581 XPATH_OP_EQUAL,
582 XPATH_OP_CMP,
583 XPATH_OP_PLUS,
584 XPATH_OP_MULT,
585 XPATH_OP_UNION,
586 XPATH_OP_ROOT,
587 XPATH_OP_NODE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000588 XPATH_OP_RESET, /* 10 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000589 XPATH_OP_COLLECT,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000590 XPATH_OP_VALUE, /* 12 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000591 XPATH_OP_VARIABLE,
592 XPATH_OP_FUNCTION,
593 XPATH_OP_ARG,
594 XPATH_OP_PREDICATE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000595 XPATH_OP_FILTER, /* 17 */
596 XPATH_OP_SORT /* 18 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000597#ifdef LIBXML_XPTR_ENABLED
598 ,XPATH_OP_RANGETO
599#endif
600} xmlXPathOp;
601
602typedef enum {
603 AXIS_ANCESTOR = 1,
604 AXIS_ANCESTOR_OR_SELF,
605 AXIS_ATTRIBUTE,
606 AXIS_CHILD,
607 AXIS_DESCENDANT,
608 AXIS_DESCENDANT_OR_SELF,
609 AXIS_FOLLOWING,
610 AXIS_FOLLOWING_SIBLING,
611 AXIS_NAMESPACE,
612 AXIS_PARENT,
613 AXIS_PRECEDING,
614 AXIS_PRECEDING_SIBLING,
Daniel Veillard45490ae2008-07-29 09:13:19 +0000615 AXIS_SELF
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000616} xmlXPathAxisVal;
617
618typedef enum {
619 NODE_TEST_NONE = 0,
620 NODE_TEST_TYPE = 1,
621 NODE_TEST_PI = 2,
622 NODE_TEST_ALL = 3,
623 NODE_TEST_NS = 4,
624 NODE_TEST_NAME = 5
625} xmlXPathTestVal;
626
627typedef enum {
628 NODE_TYPE_NODE = 0,
629 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
630 NODE_TYPE_TEXT = XML_TEXT_NODE,
Daniel Veillard45490ae2008-07-29 09:13:19 +0000631 NODE_TYPE_PI = XML_PI_NODE
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000632} xmlXPathTypeVal;
633
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000634typedef struct _xmlXPathStepOp xmlXPathStepOp;
635typedef xmlXPathStepOp *xmlXPathStepOpPtr;
636struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000637 xmlXPathOp op; /* The identifier of the operation */
638 int ch1; /* First child */
639 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000640 int value;
641 int value2;
642 int value3;
643 void *value4;
644 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000645 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000646 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000647};
648
649struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000650 int nbStep; /* Number of steps in this expression */
651 int maxStep; /* Maximum number of steps allocated */
652 xmlXPathStepOp *steps; /* ops for computation of this expression */
653 int last; /* index of last step in expression */
654 xmlChar *expr; /* the expression being computed */
Daniel Veillard4773df22004-01-23 13:15:13 +0000655 xmlDictPtr dict; /* the dictionnary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000656#ifdef DEBUG_EVAL_COUNTS
657 int nb;
658 xmlChar *string;
659#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000660#ifdef XPATH_STREAMING
661 xmlPatternPtr stream;
662#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000663};
664
665/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000666 * *
667 * Forward declarations *
668 * *
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000669 ************************************************************************/
670static void
671xmlXPathFreeValueTree(xmlNodeSetPtr obj);
672static void
673xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
674static int
675xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
676 xmlXPathStepOpPtr op, xmlNodePtr *first);
677static int
678xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +0000679 xmlXPathStepOpPtr op,
680 int isPredicate);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000681
682/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000683 * *
684 * Parser Type functions *
685 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000686 ************************************************************************/
687
688/**
689 * xmlXPathNewCompExpr:
690 *
691 * Create a new Xpath component
692 *
693 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
694 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000695static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000696xmlXPathNewCompExpr(void) {
697 xmlXPathCompExprPtr cur;
698
699 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
700 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000701 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000702 return(NULL);
703 }
704 memset(cur, 0, sizeof(xmlXPathCompExpr));
705 cur->maxStep = 10;
706 cur->nbStep = 0;
707 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
708 sizeof(xmlXPathStepOp));
709 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000710 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000711 xmlFree(cur);
712 return(NULL);
713 }
714 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
715 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000716#ifdef DEBUG_EVAL_COUNTS
717 cur->nb = 0;
718#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000719 return(cur);
720}
721
722/**
723 * xmlXPathFreeCompExpr:
724 * @comp: an XPATH comp
725 *
726 * Free up the memory allocated by @comp
727 */
728void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000729xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
730{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000731 xmlXPathStepOpPtr op;
732 int i;
733
734 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000735 return;
Daniel Veillard4773df22004-01-23 13:15:13 +0000736 if (comp->dict == NULL) {
737 for (i = 0; i < comp->nbStep; i++) {
738 op = &comp->steps[i];
739 if (op->value4 != NULL) {
740 if (op->op == XPATH_OP_VALUE)
741 xmlXPathFreeObject(op->value4);
742 else
743 xmlFree(op->value4);
744 }
745 if (op->value5 != NULL)
746 xmlFree(op->value5);
747 }
748 } else {
749 for (i = 0; i < comp->nbStep; i++) {
750 op = &comp->steps[i];
751 if (op->value4 != NULL) {
752 if (op->op == XPATH_OP_VALUE)
753 xmlXPathFreeObject(op->value4);
754 }
755 }
756 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000757 }
758 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000759 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000760 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000761#ifdef DEBUG_EVAL_COUNTS
762 if (comp->string != NULL) {
763 xmlFree(comp->string);
764 }
765#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000766#ifdef XPATH_STREAMING
767 if (comp->stream != NULL) {
768 xmlFreePatternList(comp->stream);
769 }
770#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000771 if (comp->expr != NULL) {
772 xmlFree(comp->expr);
773 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000774
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000775 xmlFree(comp);
776}
777
778/**
779 * xmlXPathCompExprAdd:
780 * @comp: the compiled expression
781 * @ch1: first child index
782 * @ch2: second child index
783 * @op: an op
784 * @value: the first int value
785 * @value2: the second int value
786 * @value3: the third int value
787 * @value4: the first string value
788 * @value5: the second string value
789 *
William M. Brack08171912003-12-29 02:52:11 +0000790 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000791 *
792 * Returns -1 in case of failure, the index otherwise
793 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000794static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000795xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
796 xmlXPathOp op, int value,
797 int value2, int value3, void *value4, void *value5) {
798 if (comp->nbStep >= comp->maxStep) {
799 xmlXPathStepOp *real;
800
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800801 if (comp->maxStep >= XPATH_MAX_STEPS) {
802 xmlXPathErrMemory(NULL, "adding step\n");
803 return(-1);
804 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000805 comp->maxStep *= 2;
806 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
807 comp->maxStep * sizeof(xmlXPathStepOp));
808 if (real == NULL) {
809 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000810 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000811 return(-1);
812 }
813 comp->steps = real;
814 }
815 comp->last = comp->nbStep;
816 comp->steps[comp->nbStep].ch1 = ch1;
817 comp->steps[comp->nbStep].ch2 = ch2;
818 comp->steps[comp->nbStep].op = op;
819 comp->steps[comp->nbStep].value = value;
820 comp->steps[comp->nbStep].value2 = value2;
821 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +0000822 if ((comp->dict != NULL) &&
823 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
824 (op == XPATH_OP_COLLECT))) {
825 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000826 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000827 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000828 xmlFree(value4);
829 } else
830 comp->steps[comp->nbStep].value4 = NULL;
831 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000832 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000833 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000834 xmlFree(value5);
835 } else
836 comp->steps[comp->nbStep].value5 = NULL;
837 } else {
838 comp->steps[comp->nbStep].value4 = value4;
839 comp->steps[comp->nbStep].value5 = value5;
840 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000841 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000842 return(comp->nbStep++);
843}
844
Daniel Veillardf06307e2001-07-03 10:35:50 +0000845/**
846 * xmlXPathCompSwap:
847 * @comp: the compiled expression
848 * @op: operation index
849 *
850 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000851 */
852static void
853xmlXPathCompSwap(xmlXPathStepOpPtr op) {
854 int tmp;
855
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000856#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000857 /*
858 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +0000859 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +0000860 * application
861 */
862 if (xmlXPathDisableOptimizer)
863 return;
864#endif
865
Daniel Veillardf06307e2001-07-03 10:35:50 +0000866 tmp = op->ch1;
867 op->ch1 = op->ch2;
868 op->ch2 = tmp;
869}
870
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000871#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
872 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
873 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000874#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
875 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
876 (op), (val), (val2), (val3), (val4), (val5))
877
Daniel Veillard45490ae2008-07-29 09:13:19 +0000878#define PUSH_LEAVE_EXPR(op, val, val2) \
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000879xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
880
Daniel Veillard45490ae2008-07-29 09:13:19 +0000881#define PUSH_UNARY_EXPR(op, ch, val, val2) \
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000882xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
883
Daniel Veillard45490ae2008-07-29 09:13:19 +0000884#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +0000885xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
886 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000887
888/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000889 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +0000890 * XPath object cache structures *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000891 * *
892 ************************************************************************/
893
894/* #define XP_DEFAULT_CACHE_ON */
895
Kasimier T. Buchcik58694692006-05-31 12:37:28 +0000896#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000897
Kasimier T. Buchcik58694692006-05-31 12:37:28 +0000898typedef struct _xmlXPathContextCache xmlXPathContextCache;
899typedef xmlXPathContextCache *xmlXPathContextCachePtr;
900struct _xmlXPathContextCache {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +0000901 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
902 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
903 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
904 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
905 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000906 int maxNodeset;
907 int maxString;
908 int maxBoolean;
909 int maxNumber;
910 int maxMisc;
911#ifdef XP_DEBUG_OBJ_USAGE
912 int dbgCachedAll;
913 int dbgCachedNodeset;
914 int dbgCachedString;
915 int dbgCachedBool;
916 int dbgCachedNumber;
917 int dbgCachedPoint;
918 int dbgCachedRange;
919 int dbgCachedLocset;
920 int dbgCachedUsers;
921 int dbgCachedXSLTTree;
Daniel Veillard45490ae2008-07-29 09:13:19 +0000922 int dbgCachedUndefined;
923
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000924
925 int dbgReusedAll;
926 int dbgReusedNodeset;
927 int dbgReusedString;
928 int dbgReusedBool;
929 int dbgReusedNumber;
930 int dbgReusedPoint;
931 int dbgReusedRange;
932 int dbgReusedLocset;
933 int dbgReusedUsers;
934 int dbgReusedXSLTTree;
935 int dbgReusedUndefined;
936
937#endif
938};
939
940/************************************************************************
941 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +0000942 * Debugging related functions *
Owen Taylor3473f882001-02-23 17:55:21 +0000943 * *
944 ************************************************************************/
945
Daniel Veillard45490ae2008-07-29 09:13:19 +0000946#define STRANGE \
Owen Taylor3473f882001-02-23 17:55:21 +0000947 xmlGenericError(xmlGenericErrorContext, \
948 "Internal error at %s:%d\n", \
949 __FILE__, __LINE__);
950
951#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000952static void
953xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000954 int i;
955 char shift[100];
956
957 for (i = 0;((i < depth) && (i < 25));i++)
958 shift[2 * i] = shift[2 * i + 1] = ' ';
959 shift[2 * i] = shift[2 * i + 1] = 0;
960 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200961 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +0000962 fprintf(output, "Node is NULL !\n");
963 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +0000964
Owen Taylor3473f882001-02-23 17:55:21 +0000965 }
966
967 if ((cur->type == XML_DOCUMENT_NODE) ||
968 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200969 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +0000970 fprintf(output, " /\n");
971 } else if (cur->type == XML_ATTRIBUTE_NODE)
972 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
973 else
974 xmlDebugDumpOneNode(output, cur, depth);
975}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000976static void
977xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000978 xmlNodePtr tmp;
979 int i;
980 char shift[100];
981
982 for (i = 0;((i < depth) && (i < 25));i++)
983 shift[2 * i] = shift[2 * i + 1] = ' ';
984 shift[2 * i] = shift[2 * i + 1] = 0;
985 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200986 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000987 fprintf(output, "Node is NULL !\n");
988 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +0000989
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000990 }
991
992 while (cur != NULL) {
993 tmp = cur;
994 cur = cur->next;
995 xmlDebugDumpOneNode(output, tmp, depth);
996 }
997}
Owen Taylor3473f882001-02-23 17:55:21 +0000998
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000999static void
1000xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001001 int i;
1002 char shift[100];
1003
1004 for (i = 0;((i < depth) && (i < 25));i++)
1005 shift[2 * i] = shift[2 * i + 1] = ' ';
1006 shift[2 * i] = shift[2 * i + 1] = 0;
1007
1008 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001009 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001010 fprintf(output, "NodeSet is NULL !\n");
1011 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001012
Owen Taylor3473f882001-02-23 17:55:21 +00001013 }
1014
Daniel Veillard911f49a2001-04-07 15:39:35 +00001015 if (cur != NULL) {
1016 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1017 for (i = 0;i < cur->nodeNr;i++) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001018 fprintf(output, "%s", shift);
Daniel Veillard911f49a2001-04-07 15:39:35 +00001019 fprintf(output, "%d", i + 1);
1020 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1021 }
Owen Taylor3473f882001-02-23 17:55:21 +00001022 }
1023}
1024
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001025static void
1026xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001027 int i;
1028 char shift[100];
1029
1030 for (i = 0;((i < depth) && (i < 25));i++)
1031 shift[2 * i] = shift[2 * i + 1] = ' ';
1032 shift[2 * i] = shift[2 * i + 1] = 0;
1033
1034 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001035 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001036 fprintf(output, "Value Tree is NULL !\n");
1037 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001038
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001039 }
1040
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001041 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001042 fprintf(output, "%d", i + 1);
1043 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1044}
Owen Taylor3473f882001-02-23 17:55:21 +00001045#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001046static void
1047xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001048 int i;
1049 char shift[100];
1050
1051 for (i = 0;((i < depth) && (i < 25));i++)
1052 shift[2 * i] = shift[2 * i + 1] = ' ';
1053 shift[2 * i] = shift[2 * i + 1] = 0;
1054
1055 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001056 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001057 fprintf(output, "LocationSet is NULL !\n");
1058 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001059
Owen Taylor3473f882001-02-23 17:55:21 +00001060 }
1061
1062 for (i = 0;i < cur->locNr;i++) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001063 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001064 fprintf(output, "%d : ", i + 1);
1065 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1066 }
1067}
Daniel Veillard017b1082001-06-21 11:20:21 +00001068#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001069
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00001070/**
1071 * xmlXPathDebugDumpObject:
1072 * @output: the FILE * to dump the output
1073 * @cur: the object to inspect
1074 * @depth: indentation level
1075 *
1076 * Dump the content of the object for debugging purposes
1077 */
1078void
1079xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001080 int i;
1081 char shift[100];
1082
Daniel Veillarda82b1822004-11-08 16:24:57 +00001083 if (output == NULL) return;
1084
Owen Taylor3473f882001-02-23 17:55:21 +00001085 for (i = 0;((i < depth) && (i < 25));i++)
1086 shift[2 * i] = shift[2 * i + 1] = ' ';
1087 shift[2 * i] = shift[2 * i + 1] = 0;
1088
Kasimier T. Buchcik97258712006-01-05 12:30:43 +00001089
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001090 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001091
1092 if (cur == NULL) {
1093 fprintf(output, "Object is empty (NULL)\n");
1094 return;
1095 }
1096 switch(cur->type) {
1097 case XPATH_UNDEFINED:
1098 fprintf(output, "Object is uninitialized\n");
1099 break;
1100 case XPATH_NODESET:
1101 fprintf(output, "Object is a Node Set :\n");
1102 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1103 break;
1104 case XPATH_XSLT_TREE:
1105 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001106 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +00001107 break;
1108 case XPATH_BOOLEAN:
1109 fprintf(output, "Object is a Boolean : ");
1110 if (cur->boolval) fprintf(output, "true\n");
1111 else fprintf(output, "false\n");
1112 break;
1113 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +00001114 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001115 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001116 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001117 break;
1118 case -1:
1119 fprintf(output, "Object is a number : -Infinity\n");
1120 break;
1121 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001122 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001123 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001124 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1125 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001126 } else {
1127 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1128 }
1129 }
Owen Taylor3473f882001-02-23 17:55:21 +00001130 break;
1131 case XPATH_STRING:
1132 fprintf(output, "Object is a string : ");
1133 xmlDebugDumpString(output, cur->stringval);
1134 fprintf(output, "\n");
1135 break;
1136 case XPATH_POINT:
1137 fprintf(output, "Object is a point : index %d in node", cur->index);
1138 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1139 fprintf(output, "\n");
1140 break;
1141 case XPATH_RANGE:
1142 if ((cur->user2 == NULL) ||
1143 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1144 fprintf(output, "Object is a collapsed range :\n");
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001145 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001146 if (cur->index >= 0)
1147 fprintf(output, "index %d in ", cur->index);
1148 fprintf(output, "node\n");
1149 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1150 depth + 1);
1151 } else {
1152 fprintf(output, "Object is a range :\n");
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001153 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001154 fprintf(output, "From ");
1155 if (cur->index >= 0)
1156 fprintf(output, "index %d in ", cur->index);
1157 fprintf(output, "node\n");
1158 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1159 depth + 1);
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001160 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001161 fprintf(output, "To ");
1162 if (cur->index2 >= 0)
1163 fprintf(output, "index %d in ", cur->index2);
1164 fprintf(output, "node\n");
1165 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1166 depth + 1);
1167 fprintf(output, "\n");
1168 }
1169 break;
1170 case XPATH_LOCATIONSET:
1171#if defined(LIBXML_XPTR_ENABLED)
1172 fprintf(output, "Object is a Location Set:\n");
1173 xmlXPathDebugDumpLocationSet(output,
1174 (xmlLocationSetPtr) cur->user, depth);
1175#endif
1176 break;
1177 case XPATH_USERS:
1178 fprintf(output, "Object is user defined\n");
1179 break;
1180 }
1181}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001182
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001183static void
1184xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001185 xmlXPathStepOpPtr op, int depth) {
1186 int i;
1187 char shift[100];
1188
1189 for (i = 0;((i < depth) && (i < 25));i++)
1190 shift[2 * i] = shift[2 * i + 1] = ' ';
1191 shift[2 * i] = shift[2 * i + 1] = 0;
1192
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001193 fprintf(output, "%s", shift);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001194 if (op == NULL) {
1195 fprintf(output, "Step is NULL\n");
1196 return;
1197 }
1198 switch (op->op) {
1199 case XPATH_OP_END:
1200 fprintf(output, "END"); break;
1201 case XPATH_OP_AND:
1202 fprintf(output, "AND"); break;
1203 case XPATH_OP_OR:
1204 fprintf(output, "OR"); break;
1205 case XPATH_OP_EQUAL:
1206 if (op->value)
1207 fprintf(output, "EQUAL =");
1208 else
1209 fprintf(output, "EQUAL !=");
1210 break;
1211 case XPATH_OP_CMP:
1212 if (op->value)
1213 fprintf(output, "CMP <");
1214 else
1215 fprintf(output, "CMP >");
1216 if (!op->value2)
1217 fprintf(output, "=");
1218 break;
1219 case XPATH_OP_PLUS:
1220 if (op->value == 0)
1221 fprintf(output, "PLUS -");
1222 else if (op->value == 1)
1223 fprintf(output, "PLUS +");
1224 else if (op->value == 2)
1225 fprintf(output, "PLUS unary -");
1226 else if (op->value == 3)
1227 fprintf(output, "PLUS unary - -");
1228 break;
1229 case XPATH_OP_MULT:
1230 if (op->value == 0)
1231 fprintf(output, "MULT *");
1232 else if (op->value == 1)
1233 fprintf(output, "MULT div");
1234 else
1235 fprintf(output, "MULT mod");
1236 break;
1237 case XPATH_OP_UNION:
1238 fprintf(output, "UNION"); break;
1239 case XPATH_OP_ROOT:
1240 fprintf(output, "ROOT"); break;
1241 case XPATH_OP_NODE:
1242 fprintf(output, "NODE"); break;
1243 case XPATH_OP_RESET:
1244 fprintf(output, "RESET"); break;
1245 case XPATH_OP_SORT:
1246 fprintf(output, "SORT"); break;
1247 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +00001248 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1249 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1250 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001251 const xmlChar *prefix = op->value4;
1252 const xmlChar *name = op->value5;
1253
1254 fprintf(output, "COLLECT ");
1255 switch (axis) {
1256 case AXIS_ANCESTOR:
1257 fprintf(output, " 'ancestors' "); break;
1258 case AXIS_ANCESTOR_OR_SELF:
1259 fprintf(output, " 'ancestors-or-self' "); break;
1260 case AXIS_ATTRIBUTE:
1261 fprintf(output, " 'attributes' "); break;
1262 case AXIS_CHILD:
1263 fprintf(output, " 'child' "); break;
1264 case AXIS_DESCENDANT:
1265 fprintf(output, " 'descendant' "); break;
1266 case AXIS_DESCENDANT_OR_SELF:
1267 fprintf(output, " 'descendant-or-self' "); break;
1268 case AXIS_FOLLOWING:
1269 fprintf(output, " 'following' "); break;
1270 case AXIS_FOLLOWING_SIBLING:
1271 fprintf(output, " 'following-siblings' "); break;
1272 case AXIS_NAMESPACE:
1273 fprintf(output, " 'namespace' "); break;
1274 case AXIS_PARENT:
1275 fprintf(output, " 'parent' "); break;
1276 case AXIS_PRECEDING:
1277 fprintf(output, " 'preceding' "); break;
1278 case AXIS_PRECEDING_SIBLING:
1279 fprintf(output, " 'preceding-sibling' "); break;
1280 case AXIS_SELF:
1281 fprintf(output, " 'self' "); break;
1282 }
1283 switch (test) {
1284 case NODE_TEST_NONE:
1285 fprintf(output, "'none' "); break;
1286 case NODE_TEST_TYPE:
1287 fprintf(output, "'type' "); break;
1288 case NODE_TEST_PI:
1289 fprintf(output, "'PI' "); break;
1290 case NODE_TEST_ALL:
1291 fprintf(output, "'all' "); break;
1292 case NODE_TEST_NS:
1293 fprintf(output, "'namespace' "); break;
1294 case NODE_TEST_NAME:
1295 fprintf(output, "'name' "); break;
1296 }
1297 switch (type) {
1298 case NODE_TYPE_NODE:
1299 fprintf(output, "'node' "); break;
1300 case NODE_TYPE_COMMENT:
1301 fprintf(output, "'comment' "); break;
1302 case NODE_TYPE_TEXT:
1303 fprintf(output, "'text' "); break;
1304 case NODE_TYPE_PI:
1305 fprintf(output, "'PI' "); break;
1306 }
1307 if (prefix != NULL)
1308 fprintf(output, "%s:", prefix);
1309 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001310 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001311 break;
1312
1313 }
1314 case XPATH_OP_VALUE: {
1315 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1316
1317 fprintf(output, "ELEM ");
1318 xmlXPathDebugDumpObject(output, object, 0);
1319 goto finish;
1320 }
1321 case XPATH_OP_VARIABLE: {
1322 const xmlChar *prefix = op->value5;
1323 const xmlChar *name = op->value4;
1324
1325 if (prefix != NULL)
1326 fprintf(output, "VARIABLE %s:%s", prefix, name);
1327 else
1328 fprintf(output, "VARIABLE %s", name);
1329 break;
1330 }
1331 case XPATH_OP_FUNCTION: {
1332 int nbargs = op->value;
1333 const xmlChar *prefix = op->value5;
1334 const xmlChar *name = op->value4;
1335
1336 if (prefix != NULL)
1337 fprintf(output, "FUNCTION %s:%s(%d args)",
1338 prefix, name, nbargs);
1339 else
1340 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1341 break;
1342 }
1343 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1344 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001345 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001346#ifdef LIBXML_XPTR_ENABLED
1347 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1348#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001349 default:
1350 fprintf(output, "UNKNOWN %d\n", op->op); return;
1351 }
1352 fprintf(output, "\n");
1353finish:
1354 if (op->ch1 >= 0)
1355 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1356 if (op->ch2 >= 0)
1357 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1358}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001359
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001360/**
1361 * xmlXPathDebugDumpCompExpr:
1362 * @output: the FILE * for the output
1363 * @comp: the precompiled XPath expression
1364 * @depth: the indentation level.
1365 *
1366 * Dumps the tree of the compiled XPath expression.
1367 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001368void
1369xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1370 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001371 int i;
1372 char shift[100];
1373
Daniel Veillarda82b1822004-11-08 16:24:57 +00001374 if ((output == NULL) || (comp == NULL)) return;
1375
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001376 for (i = 0;((i < depth) && (i < 25));i++)
1377 shift[2 * i] = shift[2 * i + 1] = ' ';
1378 shift[2 * i] = shift[2 * i + 1] = 0;
1379
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001380 fprintf(output, "%s", shift);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001381
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001382 fprintf(output, "Compiled Expression : %d elements\n",
1383 comp->nbStep);
1384 i = comp->last;
1385 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1386}
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001387
1388#ifdef XP_DEBUG_OBJ_USAGE
1389
1390/*
1391* XPath object usage related debugging variables.
1392*/
1393static int xmlXPathDebugObjCounterUndefined = 0;
1394static int xmlXPathDebugObjCounterNodeset = 0;
1395static int xmlXPathDebugObjCounterBool = 0;
1396static int xmlXPathDebugObjCounterNumber = 0;
1397static int xmlXPathDebugObjCounterString = 0;
1398static int xmlXPathDebugObjCounterPoint = 0;
1399static int xmlXPathDebugObjCounterRange = 0;
1400static int xmlXPathDebugObjCounterLocset = 0;
1401static int xmlXPathDebugObjCounterUsers = 0;
1402static int xmlXPathDebugObjCounterXSLTTree = 0;
1403static int xmlXPathDebugObjCounterAll = 0;
1404
1405static int xmlXPathDebugObjTotalUndefined = 0;
1406static int xmlXPathDebugObjTotalNodeset = 0;
1407static int xmlXPathDebugObjTotalBool = 0;
1408static int xmlXPathDebugObjTotalNumber = 0;
1409static int xmlXPathDebugObjTotalString = 0;
1410static int xmlXPathDebugObjTotalPoint = 0;
1411static int xmlXPathDebugObjTotalRange = 0;
1412static int xmlXPathDebugObjTotalLocset = 0;
1413static int xmlXPathDebugObjTotalUsers = 0;
1414static int xmlXPathDebugObjTotalXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001415static int xmlXPathDebugObjTotalAll = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001416
1417static int xmlXPathDebugObjMaxUndefined = 0;
1418static int xmlXPathDebugObjMaxNodeset = 0;
1419static int xmlXPathDebugObjMaxBool = 0;
1420static int xmlXPathDebugObjMaxNumber = 0;
1421static int xmlXPathDebugObjMaxString = 0;
1422static int xmlXPathDebugObjMaxPoint = 0;
1423static int xmlXPathDebugObjMaxRange = 0;
1424static int xmlXPathDebugObjMaxLocset = 0;
1425static int xmlXPathDebugObjMaxUsers = 0;
1426static int xmlXPathDebugObjMaxXSLTTree = 0;
1427static int xmlXPathDebugObjMaxAll = 0;
1428
1429/* REVISIT TODO: Make this static when committing */
1430static void
1431xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1432{
1433 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001434 if (ctxt->cache != NULL) {
1435 xmlXPathContextCachePtr cache =
1436 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001437
1438 cache->dbgCachedAll = 0;
1439 cache->dbgCachedNodeset = 0;
1440 cache->dbgCachedString = 0;
1441 cache->dbgCachedBool = 0;
1442 cache->dbgCachedNumber = 0;
1443 cache->dbgCachedPoint = 0;
1444 cache->dbgCachedRange = 0;
1445 cache->dbgCachedLocset = 0;
1446 cache->dbgCachedUsers = 0;
1447 cache->dbgCachedXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001448 cache->dbgCachedUndefined = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001449
1450 cache->dbgReusedAll = 0;
1451 cache->dbgReusedNodeset = 0;
1452 cache->dbgReusedString = 0;
1453 cache->dbgReusedBool = 0;
1454 cache->dbgReusedNumber = 0;
1455 cache->dbgReusedPoint = 0;
1456 cache->dbgReusedRange = 0;
1457 cache->dbgReusedLocset = 0;
1458 cache->dbgReusedUsers = 0;
1459 cache->dbgReusedXSLTTree = 0;
1460 cache->dbgReusedUndefined = 0;
1461 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00001462 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001463
1464 xmlXPathDebugObjCounterUndefined = 0;
1465 xmlXPathDebugObjCounterNodeset = 0;
1466 xmlXPathDebugObjCounterBool = 0;
1467 xmlXPathDebugObjCounterNumber = 0;
1468 xmlXPathDebugObjCounterString = 0;
1469 xmlXPathDebugObjCounterPoint = 0;
1470 xmlXPathDebugObjCounterRange = 0;
1471 xmlXPathDebugObjCounterLocset = 0;
1472 xmlXPathDebugObjCounterUsers = 0;
1473 xmlXPathDebugObjCounterXSLTTree = 0;
1474 xmlXPathDebugObjCounterAll = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001475
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001476 xmlXPathDebugObjTotalUndefined = 0;
1477 xmlXPathDebugObjTotalNodeset = 0;
1478 xmlXPathDebugObjTotalBool = 0;
1479 xmlXPathDebugObjTotalNumber = 0;
1480 xmlXPathDebugObjTotalString = 0;
1481 xmlXPathDebugObjTotalPoint = 0;
1482 xmlXPathDebugObjTotalRange = 0;
1483 xmlXPathDebugObjTotalLocset = 0;
1484 xmlXPathDebugObjTotalUsers = 0;
1485 xmlXPathDebugObjTotalXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001486 xmlXPathDebugObjTotalAll = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001487
1488 xmlXPathDebugObjMaxUndefined = 0;
1489 xmlXPathDebugObjMaxNodeset = 0;
1490 xmlXPathDebugObjMaxBool = 0;
1491 xmlXPathDebugObjMaxNumber = 0;
1492 xmlXPathDebugObjMaxString = 0;
1493 xmlXPathDebugObjMaxPoint = 0;
1494 xmlXPathDebugObjMaxRange = 0;
1495 xmlXPathDebugObjMaxLocset = 0;
1496 xmlXPathDebugObjMaxUsers = 0;
1497 xmlXPathDebugObjMaxXSLTTree = 0;
1498 xmlXPathDebugObjMaxAll = 0;
1499
1500}
1501
1502static void
1503xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1504 xmlXPathObjectType objType)
1505{
1506 int isCached = 0;
1507
1508 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001509 if (ctxt->cache != NULL) {
1510 xmlXPathContextCachePtr cache =
1511 (xmlXPathContextCachePtr) ctxt->cache;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001512
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001513 isCached = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001514
1515 cache->dbgReusedAll++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001516 switch (objType) {
1517 case XPATH_UNDEFINED:
1518 cache->dbgReusedUndefined++;
1519 break;
1520 case XPATH_NODESET:
1521 cache->dbgReusedNodeset++;
1522 break;
1523 case XPATH_BOOLEAN:
1524 cache->dbgReusedBool++;
1525 break;
1526 case XPATH_NUMBER:
1527 cache->dbgReusedNumber++;
1528 break;
1529 case XPATH_STRING:
1530 cache->dbgReusedString++;
1531 break;
1532 case XPATH_POINT:
1533 cache->dbgReusedPoint++;
1534 break;
1535 case XPATH_RANGE:
1536 cache->dbgReusedRange++;
1537 break;
1538 case XPATH_LOCATIONSET:
1539 cache->dbgReusedLocset++;
1540 break;
1541 case XPATH_USERS:
1542 cache->dbgReusedUsers++;
1543 break;
1544 case XPATH_XSLT_TREE:
1545 cache->dbgReusedXSLTTree++;
1546 break;
1547 default:
1548 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001549 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001550 }
1551 }
1552
1553 switch (objType) {
1554 case XPATH_UNDEFINED:
1555 if (! isCached)
1556 xmlXPathDebugObjTotalUndefined++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001557 xmlXPathDebugObjCounterUndefined++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001558 if (xmlXPathDebugObjCounterUndefined >
1559 xmlXPathDebugObjMaxUndefined)
1560 xmlXPathDebugObjMaxUndefined =
1561 xmlXPathDebugObjCounterUndefined;
1562 break;
1563 case XPATH_NODESET:
1564 if (! isCached)
1565 xmlXPathDebugObjTotalNodeset++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001566 xmlXPathDebugObjCounterNodeset++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001567 if (xmlXPathDebugObjCounterNodeset >
1568 xmlXPathDebugObjMaxNodeset)
1569 xmlXPathDebugObjMaxNodeset =
1570 xmlXPathDebugObjCounterNodeset;
1571 break;
1572 case XPATH_BOOLEAN:
1573 if (! isCached)
1574 xmlXPathDebugObjTotalBool++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001575 xmlXPathDebugObjCounterBool++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001576 if (xmlXPathDebugObjCounterBool >
1577 xmlXPathDebugObjMaxBool)
1578 xmlXPathDebugObjMaxBool =
1579 xmlXPathDebugObjCounterBool;
1580 break;
1581 case XPATH_NUMBER:
1582 if (! isCached)
1583 xmlXPathDebugObjTotalNumber++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001584 xmlXPathDebugObjCounterNumber++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001585 if (xmlXPathDebugObjCounterNumber >
1586 xmlXPathDebugObjMaxNumber)
1587 xmlXPathDebugObjMaxNumber =
1588 xmlXPathDebugObjCounterNumber;
1589 break;
1590 case XPATH_STRING:
1591 if (! isCached)
1592 xmlXPathDebugObjTotalString++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001593 xmlXPathDebugObjCounterString++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001594 if (xmlXPathDebugObjCounterString >
1595 xmlXPathDebugObjMaxString)
1596 xmlXPathDebugObjMaxString =
1597 xmlXPathDebugObjCounterString;
1598 break;
1599 case XPATH_POINT:
1600 if (! isCached)
1601 xmlXPathDebugObjTotalPoint++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001602 xmlXPathDebugObjCounterPoint++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001603 if (xmlXPathDebugObjCounterPoint >
1604 xmlXPathDebugObjMaxPoint)
1605 xmlXPathDebugObjMaxPoint =
1606 xmlXPathDebugObjCounterPoint;
1607 break;
1608 case XPATH_RANGE:
1609 if (! isCached)
1610 xmlXPathDebugObjTotalRange++;
1611 xmlXPathDebugObjCounterRange++;
1612 if (xmlXPathDebugObjCounterRange >
1613 xmlXPathDebugObjMaxRange)
1614 xmlXPathDebugObjMaxRange =
1615 xmlXPathDebugObjCounterRange;
1616 break;
1617 case XPATH_LOCATIONSET:
1618 if (! isCached)
1619 xmlXPathDebugObjTotalLocset++;
1620 xmlXPathDebugObjCounterLocset++;
1621 if (xmlXPathDebugObjCounterLocset >
1622 xmlXPathDebugObjMaxLocset)
1623 xmlXPathDebugObjMaxLocset =
1624 xmlXPathDebugObjCounterLocset;
1625 break;
1626 case XPATH_USERS:
1627 if (! isCached)
1628 xmlXPathDebugObjTotalUsers++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001629 xmlXPathDebugObjCounterUsers++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001630 if (xmlXPathDebugObjCounterUsers >
1631 xmlXPathDebugObjMaxUsers)
1632 xmlXPathDebugObjMaxUsers =
1633 xmlXPathDebugObjCounterUsers;
1634 break;
1635 case XPATH_XSLT_TREE:
1636 if (! isCached)
1637 xmlXPathDebugObjTotalXSLTTree++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001638 xmlXPathDebugObjCounterXSLTTree++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001639 if (xmlXPathDebugObjCounterXSLTTree >
1640 xmlXPathDebugObjMaxXSLTTree)
1641 xmlXPathDebugObjMaxXSLTTree =
1642 xmlXPathDebugObjCounterXSLTTree;
1643 break;
1644 default:
1645 break;
1646 }
1647 if (! isCached)
1648 xmlXPathDebugObjTotalAll++;
1649 xmlXPathDebugObjCounterAll++;
1650 if (xmlXPathDebugObjCounterAll >
1651 xmlXPathDebugObjMaxAll)
1652 xmlXPathDebugObjMaxAll =
1653 xmlXPathDebugObjCounterAll;
1654}
1655
1656static void
1657xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1658 xmlXPathObjectType objType)
1659{
1660 int isCached = 0;
1661
1662 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001663 if (ctxt->cache != NULL) {
1664 xmlXPathContextCachePtr cache =
1665 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001666
Daniel Veillard45490ae2008-07-29 09:13:19 +00001667 isCached = 1;
1668
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001669 cache->dbgCachedAll++;
1670 switch (objType) {
1671 case XPATH_UNDEFINED:
1672 cache->dbgCachedUndefined++;
1673 break;
1674 case XPATH_NODESET:
1675 cache->dbgCachedNodeset++;
1676 break;
1677 case XPATH_BOOLEAN:
1678 cache->dbgCachedBool++;
1679 break;
1680 case XPATH_NUMBER:
1681 cache->dbgCachedNumber++;
1682 break;
1683 case XPATH_STRING:
1684 cache->dbgCachedString++;
1685 break;
1686 case XPATH_POINT:
1687 cache->dbgCachedPoint++;
1688 break;
1689 case XPATH_RANGE:
1690 cache->dbgCachedRange++;
1691 break;
1692 case XPATH_LOCATIONSET:
1693 cache->dbgCachedLocset++;
1694 break;
1695 case XPATH_USERS:
1696 cache->dbgCachedUsers++;
1697 break;
1698 case XPATH_XSLT_TREE:
1699 cache->dbgCachedXSLTTree++;
1700 break;
1701 default:
1702 break;
1703 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00001704
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001705 }
1706 }
1707 switch (objType) {
1708 case XPATH_UNDEFINED:
1709 xmlXPathDebugObjCounterUndefined--;
1710 break;
1711 case XPATH_NODESET:
1712 xmlXPathDebugObjCounterNodeset--;
1713 break;
1714 case XPATH_BOOLEAN:
1715 xmlXPathDebugObjCounterBool--;
1716 break;
1717 case XPATH_NUMBER:
1718 xmlXPathDebugObjCounterNumber--;
1719 break;
1720 case XPATH_STRING:
1721 xmlXPathDebugObjCounterString--;
1722 break;
1723 case XPATH_POINT:
1724 xmlXPathDebugObjCounterPoint--;
1725 break;
1726 case XPATH_RANGE:
1727 xmlXPathDebugObjCounterRange--;
1728 break;
1729 case XPATH_LOCATIONSET:
1730 xmlXPathDebugObjCounterLocset--;
1731 break;
1732 case XPATH_USERS:
1733 xmlXPathDebugObjCounterUsers--;
1734 break;
1735 case XPATH_XSLT_TREE:
1736 xmlXPathDebugObjCounterXSLTTree--;
1737 break;
1738 default:
1739 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001740 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001741 xmlXPathDebugObjCounterAll--;
1742}
1743
1744/* REVISIT TODO: Make this static when committing */
1745static void
1746xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
1747{
1748 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
1749 reqXSLTTree, reqUndefined;
1750 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
1751 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
1752 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
1753 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
1754 int leftObjs = xmlXPathDebugObjCounterAll;
1755
1756 reqAll = xmlXPathDebugObjTotalAll;
1757 reqNodeset = xmlXPathDebugObjTotalNodeset;
1758 reqString = xmlXPathDebugObjTotalString;
1759 reqBool = xmlXPathDebugObjTotalBool;
1760 reqNumber = xmlXPathDebugObjTotalNumber;
1761 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
1762 reqUndefined = xmlXPathDebugObjTotalUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001763
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001764 printf("# XPath object usage:\n");
1765
1766 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001767 if (ctxt->cache != NULL) {
1768 xmlXPathContextCachePtr cache =
1769 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001770
1771 reAll = cache->dbgReusedAll;
1772 reqAll += reAll;
1773 reNodeset = cache->dbgReusedNodeset;
1774 reqNodeset += reNodeset;
1775 reString = cache->dbgReusedString;
1776 reqString += reString;
1777 reBool = cache->dbgReusedBool;
1778 reqBool += reBool;
1779 reNumber = cache->dbgReusedNumber;
1780 reqNumber += reNumber;
1781 reXSLTTree = cache->dbgReusedXSLTTree;
1782 reqXSLTTree += reXSLTTree;
1783 reUndefined = cache->dbgReusedUndefined;
1784 reqUndefined += reUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001785
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001786 caAll = cache->dbgCachedAll;
1787 caBool = cache->dbgCachedBool;
1788 caNodeset = cache->dbgCachedNodeset;
1789 caString = cache->dbgCachedString;
1790 caNumber = cache->dbgCachedNumber;
1791 caXSLTTree = cache->dbgCachedXSLTTree;
1792 caUndefined = cache->dbgCachedUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001793
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001794 if (cache->nodesetObjs)
1795 leftObjs -= cache->nodesetObjs->number;
1796 if (cache->stringObjs)
1797 leftObjs -= cache->stringObjs->number;
1798 if (cache->booleanObjs)
1799 leftObjs -= cache->booleanObjs->number;
1800 if (cache->numberObjs)
1801 leftObjs -= cache->numberObjs->number;
1802 if (cache->miscObjs)
1803 leftObjs -= cache->miscObjs->number;
1804 }
1805 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00001806
1807 printf("# all\n");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001808 printf("# total : %d\n", reqAll);
1809 printf("# left : %d\n", leftObjs);
1810 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
1811 printf("# reused : %d\n", reAll);
1812 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
1813
1814 printf("# node-sets\n");
1815 printf("# total : %d\n", reqNodeset);
1816 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
1817 printf("# reused : %d\n", reNodeset);
1818 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
1819
1820 printf("# strings\n");
1821 printf("# total : %d\n", reqString);
1822 printf("# created: %d\n", xmlXPathDebugObjTotalString);
1823 printf("# reused : %d\n", reString);
1824 printf("# max : %d\n", xmlXPathDebugObjMaxString);
1825
1826 printf("# booleans\n");
1827 printf("# total : %d\n", reqBool);
1828 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
1829 printf("# reused : %d\n", reBool);
1830 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
1831
1832 printf("# numbers\n");
1833 printf("# total : %d\n", reqNumber);
1834 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
1835 printf("# reused : %d\n", reNumber);
1836 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
1837
1838 printf("# XSLT result tree fragments\n");
1839 printf("# total : %d\n", reqXSLTTree);
1840 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
1841 printf("# reused : %d\n", reXSLTTree);
1842 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
1843
1844 printf("# undefined\n");
1845 printf("# total : %d\n", reqUndefined);
1846 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
1847 printf("# reused : %d\n", reUndefined);
1848 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
1849
1850}
1851
1852#endif /* XP_DEBUG_OBJ_USAGE */
1853
Daniel Veillard017b1082001-06-21 11:20:21 +00001854#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001855
1856/************************************************************************
1857 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001858 * XPath object caching *
1859 * *
1860 ************************************************************************/
1861
1862/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001863 * xmlXPathNewCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001864 *
1865 * Create a new object cache
1866 *
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001867 * Returns the xmlXPathCache just allocated.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001868 */
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001869static xmlXPathContextCachePtr
1870xmlXPathNewCache(void)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001871{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001872 xmlXPathContextCachePtr ret;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001873
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001874 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001875 if (ret == NULL) {
1876 xmlXPathErrMemory(NULL, "creating object cache\n");
1877 return(NULL);
1878 }
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001879 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001880 ret->maxNodeset = 100;
1881 ret->maxString = 100;
1882 ret->maxBoolean = 100;
1883 ret->maxNumber = 100;
1884 ret->maxMisc = 100;
1885 return(ret);
1886}
1887
1888static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001889xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001890{
1891 int i;
1892 xmlXPathObjectPtr obj;
1893
1894 if (list == NULL)
1895 return;
1896
1897 for (i = 0; i < list->number; i++) {
1898 obj = list->items[i];
1899 /*
1900 * Note that it is already assured that we don't need to
1901 * look out for namespace nodes in the node-set.
1902 */
1903 if (obj->nodesetval != NULL) {
1904 if (obj->nodesetval->nodeTab != NULL)
1905 xmlFree(obj->nodesetval->nodeTab);
1906 xmlFree(obj->nodesetval);
1907 }
1908 xmlFree(obj);
1909#ifdef XP_DEBUG_OBJ_USAGE
1910 xmlXPathDebugObjCounterAll--;
1911#endif
1912 }
1913 xmlPointerListFree(list);
1914}
1915
1916static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001917xmlXPathFreeCache(xmlXPathContextCachePtr cache)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001918{
1919 if (cache == NULL)
1920 return;
1921 if (cache->nodesetObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001922 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001923 if (cache->stringObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001924 xmlXPathCacheFreeObjectList(cache->stringObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001925 if (cache->booleanObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001926 xmlXPathCacheFreeObjectList(cache->booleanObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001927 if (cache->numberObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001928 xmlXPathCacheFreeObjectList(cache->numberObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001929 if (cache->miscObjs)
Daniel Veillard45490ae2008-07-29 09:13:19 +00001930 xmlXPathCacheFreeObjectList(cache->miscObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001931 xmlFree(cache);
1932}
1933
1934/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001935 * xmlXPathContextSetCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001936 *
1937 * @ctxt: the XPath context
1938 * @active: enables/disables (creates/frees) the cache
Daniel Veillard45490ae2008-07-29 09:13:19 +00001939 * @value: a value with semantics dependant on @options
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001940 * @options: options (currently only the value 0 is used)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001941 *
1942 * Creates/frees an object cache on the XPath context.
1943 * If activates XPath objects (xmlXPathObject) will be cached internally
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001944 * to be reused.
1945 * @options:
1946 * 0: This will set the XPath object caching:
1947 * @value:
1948 * This will set the maximum number of XPath objects
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001949 * to be cached per slot
1950 * There are 5 slots for: node-set, string, number, boolean, and
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001951 * misc objects. Use <0 for the default number (100).
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001952 * Other values for @options have currently no effect.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001953 *
1954 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1955 */
1956int
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001957xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1958 int active,
1959 int value,
1960 int options)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001961{
1962 if (ctxt == NULL)
1963 return(-1);
1964 if (active) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001965 xmlXPathContextCachePtr cache;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001966
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001967 if (ctxt->cache == NULL) {
1968 ctxt->cache = xmlXPathNewCache();
1969 if (ctxt->cache == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001970 return(-1);
1971 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001972 cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001973 if (options == 0) {
1974 if (value < 0)
1975 value = 100;
1976 cache->maxNodeset = value;
1977 cache->maxString = value;
1978 cache->maxNumber = value;
1979 cache->maxBoolean = value;
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001980 cache->maxMisc = value;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001981 }
1982 } else if (ctxt->cache != NULL) {
1983 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1984 ctxt->cache = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001985 }
1986 return(0);
1987}
1988
1989/**
1990 * xmlXPathCacheWrapNodeSet:
1991 * @ctxt: the XPath context
1992 * @val: the NodePtr value
1993 *
1994 * This is the cached version of xmlXPathWrapNodeSet().
1995 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1996 *
1997 * Returns the created or reused object.
1998 */
1999static xmlXPathObjectPtr
2000xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002001{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002002 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2003 xmlXPathContextCachePtr cache =
2004 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002005
2006 if ((cache->miscObjs != NULL) &&
2007 (cache->miscObjs->number != 0))
2008 {
2009 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002010
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002011 ret = (xmlXPathObjectPtr)
2012 cache->miscObjs->items[--cache->miscObjs->number];
2013 ret->type = XPATH_NODESET;
2014 ret->nodesetval = val;
2015#ifdef XP_DEBUG_OBJ_USAGE
2016 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2017#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00002018 return(ret);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002019 }
2020 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00002021
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002022 return(xmlXPathWrapNodeSet(val));
Daniel Veillard45490ae2008-07-29 09:13:19 +00002023
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002024}
2025
2026/**
2027 * xmlXPathCacheWrapString:
2028 * @ctxt: the XPath context
2029 * @val: the xmlChar * value
2030 *
2031 * This is the cached version of xmlXPathWrapString().
2032 * Wraps the @val string into an XPath object.
2033 *
2034 * Returns the created or reused object.
2035 */
2036static xmlXPathObjectPtr
2037xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002038{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002039 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2040 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002041
2042 if ((cache->stringObjs != NULL) &&
2043 (cache->stringObjs->number != 0))
2044 {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002045
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002046 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002047
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002048 ret = (xmlXPathObjectPtr)
2049 cache->stringObjs->items[--cache->stringObjs->number];
2050 ret->type = XPATH_STRING;
2051 ret->stringval = val;
2052#ifdef XP_DEBUG_OBJ_USAGE
2053 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2054#endif
2055 return(ret);
2056 } else if ((cache->miscObjs != NULL) &&
2057 (cache->miscObjs->number != 0))
2058 {
2059 xmlXPathObjectPtr ret;
2060 /*
2061 * Fallback to misc-cache.
2062 */
2063 ret = (xmlXPathObjectPtr)
2064 cache->miscObjs->items[--cache->miscObjs->number];
2065
2066 ret->type = XPATH_STRING;
2067 ret->stringval = val;
2068#ifdef XP_DEBUG_OBJ_USAGE
2069 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2070#endif
2071 return(ret);
2072 }
2073 }
2074 return(xmlXPathWrapString(val));
2075}
2076
2077/**
2078 * xmlXPathCacheNewNodeSet:
2079 * @ctxt: the XPath context
2080 * @val: the NodePtr value
2081 *
2082 * This is the cached version of xmlXPathNewNodeSet().
2083 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2084 * it with the single Node @val
2085 *
2086 * Returns the created or reused object.
2087 */
2088static xmlXPathObjectPtr
2089xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2090{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002091 if ((ctxt != NULL) && (ctxt->cache)) {
2092 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002093
2094 if ((cache->nodesetObjs != NULL) &&
2095 (cache->nodesetObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002096 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002097 xmlXPathObjectPtr ret;
2098 /*
2099 * Use the nodset-cache.
Daniel Veillard45490ae2008-07-29 09:13:19 +00002100 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002101 ret = (xmlXPathObjectPtr)
2102 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2103 ret->type = XPATH_NODESET;
2104 ret->boolval = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002105 if (val) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002106 if ((ret->nodesetval->nodeMax == 0) ||
2107 (val->type == XML_NAMESPACE_DECL))
2108 {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002109 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002110 } else {
2111 ret->nodesetval->nodeTab[0] = val;
2112 ret->nodesetval->nodeNr = 1;
2113 }
2114 }
2115#ifdef XP_DEBUG_OBJ_USAGE
2116 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2117#endif
2118 return(ret);
2119 } else if ((cache->miscObjs != NULL) &&
2120 (cache->miscObjs->number != 0))
2121 {
2122 xmlXPathObjectPtr ret;
2123 /*
2124 * Fallback to misc-cache.
2125 */
2126
2127 ret = (xmlXPathObjectPtr)
2128 cache->miscObjs->items[--cache->miscObjs->number];
2129
2130 ret->type = XPATH_NODESET;
2131 ret->boolval = 0;
2132 ret->nodesetval = xmlXPathNodeSetCreate(val);
2133#ifdef XP_DEBUG_OBJ_USAGE
2134 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2135#endif
2136 return(ret);
2137 }
2138 }
2139 return(xmlXPathNewNodeSet(val));
2140}
2141
2142/**
2143 * xmlXPathCacheNewCString:
2144 * @ctxt: the XPath context
2145 * @val: the char * value
2146 *
2147 * This is the cached version of xmlXPathNewCString().
2148 * Acquire an xmlXPathObjectPtr of type string and of value @val
2149 *
2150 * Returns the created or reused object.
2151 */
2152static xmlXPathObjectPtr
2153xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002154{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002155 if ((ctxt != NULL) && (ctxt->cache)) {
2156 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002157
2158 if ((cache->stringObjs != NULL) &&
2159 (cache->stringObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002160 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002161 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002162
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002163 ret = (xmlXPathObjectPtr)
2164 cache->stringObjs->items[--cache->stringObjs->number];
2165
2166 ret->type = XPATH_STRING;
2167 ret->stringval = xmlStrdup(BAD_CAST val);
2168#ifdef XP_DEBUG_OBJ_USAGE
2169 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2170#endif
2171 return(ret);
2172 } else if ((cache->miscObjs != NULL) &&
2173 (cache->miscObjs->number != 0))
2174 {
2175 xmlXPathObjectPtr ret;
2176
2177 ret = (xmlXPathObjectPtr)
2178 cache->miscObjs->items[--cache->miscObjs->number];
2179
2180 ret->type = XPATH_STRING;
2181 ret->stringval = xmlStrdup(BAD_CAST val);
2182#ifdef XP_DEBUG_OBJ_USAGE
2183 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2184#endif
2185 return(ret);
2186 }
2187 }
2188 return(xmlXPathNewCString(val));
2189}
2190
2191/**
2192 * xmlXPathCacheNewString:
2193 * @ctxt: the XPath context
2194 * @val: the xmlChar * value
2195 *
2196 * This is the cached version of xmlXPathNewString().
2197 * Acquire an xmlXPathObjectPtr of type string and of value @val
2198 *
2199 * Returns the created or reused object.
2200 */
2201static xmlXPathObjectPtr
2202xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002203{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002204 if ((ctxt != NULL) && (ctxt->cache)) {
2205 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002206
2207 if ((cache->stringObjs != NULL) &&
2208 (cache->stringObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002209 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002210 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002211
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002212 ret = (xmlXPathObjectPtr)
2213 cache->stringObjs->items[--cache->stringObjs->number];
2214 ret->type = XPATH_STRING;
2215 if (val != NULL)
2216 ret->stringval = xmlStrdup(val);
2217 else
2218 ret->stringval = xmlStrdup((const xmlChar *)"");
2219#ifdef XP_DEBUG_OBJ_USAGE
2220 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2221#endif
2222 return(ret);
2223 } else if ((cache->miscObjs != NULL) &&
2224 (cache->miscObjs->number != 0))
2225 {
2226 xmlXPathObjectPtr ret;
2227
2228 ret = (xmlXPathObjectPtr)
2229 cache->miscObjs->items[--cache->miscObjs->number];
2230
2231 ret->type = XPATH_STRING;
2232 if (val != NULL)
2233 ret->stringval = xmlStrdup(val);
2234 else
2235 ret->stringval = xmlStrdup((const xmlChar *)"");
2236#ifdef XP_DEBUG_OBJ_USAGE
2237 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2238#endif
2239 return(ret);
2240 }
2241 }
2242 return(xmlXPathNewString(val));
2243}
2244
2245/**
2246 * xmlXPathCacheNewBoolean:
2247 * @ctxt: the XPath context
2248 * @val: the boolean value
2249 *
2250 * This is the cached version of xmlXPathNewBoolean().
2251 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2252 *
2253 * Returns the created or reused object.
2254 */
2255static xmlXPathObjectPtr
2256xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002257{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002258 if ((ctxt != NULL) && (ctxt->cache)) {
2259 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002260
2261 if ((cache->booleanObjs != NULL) &&
2262 (cache->booleanObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002263 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002264 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002265
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002266 ret = (xmlXPathObjectPtr)
2267 cache->booleanObjs->items[--cache->booleanObjs->number];
2268 ret->type = XPATH_BOOLEAN;
2269 ret->boolval = (val != 0);
2270#ifdef XP_DEBUG_OBJ_USAGE
2271 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2272#endif
2273 return(ret);
2274 } else if ((cache->miscObjs != NULL) &&
2275 (cache->miscObjs->number != 0))
2276 {
2277 xmlXPathObjectPtr ret;
2278
2279 ret = (xmlXPathObjectPtr)
2280 cache->miscObjs->items[--cache->miscObjs->number];
2281
2282 ret->type = XPATH_BOOLEAN;
2283 ret->boolval = (val != 0);
2284#ifdef XP_DEBUG_OBJ_USAGE
2285 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2286#endif
2287 return(ret);
2288 }
2289 }
2290 return(xmlXPathNewBoolean(val));
2291}
2292
2293/**
2294 * xmlXPathCacheNewFloat:
2295 * @ctxt: the XPath context
2296 * @val: the double value
2297 *
2298 * This is the cached version of xmlXPathNewFloat().
2299 * Acquires an xmlXPathObjectPtr of type double and of value @val
2300 *
2301 * Returns the created or reused object.
2302 */
2303static xmlXPathObjectPtr
2304xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2305{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002306 if ((ctxt != NULL) && (ctxt->cache)) {
2307 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002308
2309 if ((cache->numberObjs != NULL) &&
2310 (cache->numberObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002311 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002312 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002313
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002314 ret = (xmlXPathObjectPtr)
2315 cache->numberObjs->items[--cache->numberObjs->number];
2316 ret->type = XPATH_NUMBER;
2317 ret->floatval = val;
2318#ifdef XP_DEBUG_OBJ_USAGE
2319 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2320#endif
2321 return(ret);
2322 } else if ((cache->miscObjs != NULL) &&
2323 (cache->miscObjs->number != 0))
2324 {
2325 xmlXPathObjectPtr ret;
2326
2327 ret = (xmlXPathObjectPtr)
2328 cache->miscObjs->items[--cache->miscObjs->number];
2329
2330 ret->type = XPATH_NUMBER;
2331 ret->floatval = val;
2332#ifdef XP_DEBUG_OBJ_USAGE
2333 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2334#endif
2335 return(ret);
2336 }
2337 }
2338 return(xmlXPathNewFloat(val));
2339}
2340
2341/**
2342 * xmlXPathCacheConvertString:
2343 * @ctxt: the XPath context
2344 * @val: an XPath object
2345 *
2346 * This is the cached version of xmlXPathConvertString().
2347 * Converts an existing object to its string() equivalent
2348 *
2349 * Returns a created or reused object, the old one is freed (cached)
2350 * (or the operation is done directly on @val)
2351 */
2352
2353static xmlXPathObjectPtr
2354xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002355 xmlChar *res = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002356
2357 if (val == NULL)
2358 return(xmlXPathCacheNewCString(ctxt, ""));
2359
2360 switch (val->type) {
2361 case XPATH_UNDEFINED:
2362#ifdef DEBUG_EXPR
2363 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2364#endif
2365 break;
2366 case XPATH_NODESET:
2367 case XPATH_XSLT_TREE:
2368 res = xmlXPathCastNodeSetToString(val->nodesetval);
2369 break;
2370 case XPATH_STRING:
2371 return(val);
2372 case XPATH_BOOLEAN:
2373 res = xmlXPathCastBooleanToString(val->boolval);
2374 break;
2375 case XPATH_NUMBER:
2376 res = xmlXPathCastNumberToString(val->floatval);
2377 break;
2378 case XPATH_USERS:
2379 case XPATH_POINT:
2380 case XPATH_RANGE:
2381 case XPATH_LOCATIONSET:
2382 TODO;
2383 break;
2384 }
2385 xmlXPathReleaseObject(ctxt, val);
2386 if (res == NULL)
2387 return(xmlXPathCacheNewCString(ctxt, ""));
2388 return(xmlXPathCacheWrapString(ctxt, res));
2389}
2390
2391/**
2392 * xmlXPathCacheObjectCopy:
2393 * @ctxt: the XPath context
2394 * @val: the original object
2395 *
2396 * This is the cached version of xmlXPathObjectCopy().
2397 * Acquire a copy of a given object
2398 *
2399 * Returns a created or reused created object.
2400 */
2401static xmlXPathObjectPtr
2402xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2403{
2404 if (val == NULL)
2405 return(NULL);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002406
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002407 if (XP_HAS_CACHE(ctxt)) {
2408 switch (val->type) {
2409 case XPATH_NODESET:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002410 return(xmlXPathCacheWrapNodeSet(ctxt,
2411 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002412 case XPATH_STRING:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002413 return(xmlXPathCacheNewString(ctxt, val->stringval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002414 case XPATH_BOOLEAN:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002415 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002416 case XPATH_NUMBER:
2417 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2418 default:
2419 break;
2420 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002421 }
2422 return(xmlXPathObjectCopy(val));
2423}
2424
2425/**
2426 * xmlXPathCacheConvertBoolean:
2427 * @ctxt: the XPath context
2428 * @val: an XPath object
2429 *
2430 * This is the cached version of xmlXPathConvertBoolean().
2431 * Converts an existing object to its boolean() equivalent
2432 *
2433 * Returns a created or reused object, the old one is freed (or the operation
2434 * is done directly on @val)
2435 */
2436static xmlXPathObjectPtr
2437xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2438 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002439
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002440 if (val == NULL)
2441 return(xmlXPathCacheNewBoolean(ctxt, 0));
2442 if (val->type == XPATH_BOOLEAN)
2443 return(val);
2444 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2445 xmlXPathReleaseObject(ctxt, val);
2446 return(ret);
2447}
2448
2449/**
2450 * xmlXPathCacheConvertNumber:
2451 * @ctxt: the XPath context
2452 * @val: an XPath object
2453 *
2454 * This is the cached version of xmlXPathConvertNumber().
2455 * Converts an existing object to its number() equivalent
2456 *
2457 * Returns a created or reused object, the old one is freed (or the operation
2458 * is done directly on @val)
2459 */
2460static xmlXPathObjectPtr
2461xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2462 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002463
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002464 if (val == NULL)
2465 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2466 if (val->type == XPATH_NUMBER)
2467 return(val);
2468 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2469 xmlXPathReleaseObject(ctxt, val);
2470 return(ret);
2471}
2472
2473/************************************************************************
2474 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +00002475 * Parser stacks related functions and macros *
Owen Taylor3473f882001-02-23 17:55:21 +00002476 * *
2477 ************************************************************************/
2478
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002479/**
Daniel Veillardf5048b32011-08-18 17:10:13 +08002480 * xmlXPathSetFrame:
2481 * @ctxt: an XPath parser context
2482 *
2483 * Set the callee evaluation frame
2484 *
2485 * Returns the previous frame value to be restored once done
2486 */
2487static int
2488xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2489 int ret;
2490
2491 if (ctxt == NULL)
2492 return(0);
2493 ret = ctxt->valueFrame;
2494 ctxt->valueFrame = ctxt->valueNr;
2495 return(ret);
2496}
2497
2498/**
2499 * xmlXPathPopFrame:
2500 * @ctxt: an XPath parser context
2501 * @frame: the previous frame value
2502 *
2503 * Remove the callee evaluation frame
2504 */
2505static void
2506xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2507 if (ctxt == NULL)
2508 return;
2509 if (ctxt->valueNr < ctxt->valueFrame) {
2510 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2511 }
2512 ctxt->valueFrame = frame;
2513}
2514
2515/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002516 * valuePop:
2517 * @ctxt: an XPath evaluation context
2518 *
2519 * Pops the top XPath object from the value stack
2520 *
2521 * Returns the XPath object just removed
2522 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002523xmlXPathObjectPtr
Daniel Veillard1c732d22002-11-30 11:22:59 +00002524valuePop(xmlXPathParserContextPtr ctxt)
2525{
2526 xmlXPathObjectPtr ret;
2527
Daniel Veillarda82b1822004-11-08 16:24:57 +00002528 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
Daniel Veillard24505b02005-07-28 23:49:35 +00002529 return (NULL);
Daniel Veillardf5048b32011-08-18 17:10:13 +08002530
2531 if (ctxt->valueNr <= ctxt->valueFrame) {
2532 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2533 return (NULL);
2534 }
2535
Daniel Veillard1c732d22002-11-30 11:22:59 +00002536 ctxt->valueNr--;
2537 if (ctxt->valueNr > 0)
2538 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2539 else
2540 ctxt->value = NULL;
2541 ret = ctxt->valueTab[ctxt->valueNr];
Daniel Veillard24505b02005-07-28 23:49:35 +00002542 ctxt->valueTab[ctxt->valueNr] = NULL;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002543 return (ret);
2544}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002545/**
2546 * valuePush:
2547 * @ctxt: an XPath evaluation context
2548 * @value: the XPath object
2549 *
2550 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002551 *
2552 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002553 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002554int
Daniel Veillard1c732d22002-11-30 11:22:59 +00002555valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2556{
Daniel Veillarda82b1822004-11-08 16:24:57 +00002557 if ((ctxt == NULL) || (value == NULL)) return(-1);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002558 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002559 xmlXPathObjectPtr *tmp;
2560
Daniel Veillardcd852ad2012-07-30 10:12:18 +08002561 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2562 xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
2563 ctxt->error = XPATH_MEMORY_ERROR;
2564 return (0);
2565 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002566 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2567 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00002568 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002569 if (tmp == NULL) {
Daniel Veillardcd852ad2012-07-30 10:12:18 +08002570 xmlXPathErrMemory(NULL, "pushing value\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08002571 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002572 return (0);
2573 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002574 ctxt->valueMax *= 2;
2575 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002576 }
2577 ctxt->valueTab[ctxt->valueNr] = value;
2578 ctxt->value = value;
2579 return (ctxt->valueNr++);
2580}
Owen Taylor3473f882001-02-23 17:55:21 +00002581
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002582/**
2583 * xmlXPathPopBoolean:
2584 * @ctxt: an XPath parser context
2585 *
2586 * Pops a boolean from the stack, handling conversion if needed.
2587 * Check error with #xmlXPathCheckError.
2588 *
2589 * Returns the boolean
2590 */
2591int
2592xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2593 xmlXPathObjectPtr obj;
2594 int ret;
2595
2596 obj = valuePop(ctxt);
2597 if (obj == NULL) {
2598 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2599 return(0);
2600 }
William M. Brack08171912003-12-29 02:52:11 +00002601 if (obj->type != XPATH_BOOLEAN)
2602 ret = xmlXPathCastToBoolean(obj);
2603 else
2604 ret = obj->boolval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002605 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002606 return(ret);
2607}
2608
2609/**
2610 * xmlXPathPopNumber:
2611 * @ctxt: an XPath parser context
2612 *
2613 * Pops a number from the stack, handling conversion if needed.
2614 * Check error with #xmlXPathCheckError.
2615 *
2616 * Returns the number
2617 */
2618double
2619xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2620 xmlXPathObjectPtr obj;
2621 double ret;
2622
2623 obj = valuePop(ctxt);
2624 if (obj == NULL) {
2625 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2626 return(0);
2627 }
William M. Brack08171912003-12-29 02:52:11 +00002628 if (obj->type != XPATH_NUMBER)
2629 ret = xmlXPathCastToNumber(obj);
2630 else
2631 ret = obj->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002632 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002633 return(ret);
2634}
2635
2636/**
2637 * xmlXPathPopString:
2638 * @ctxt: an XPath parser context
2639 *
2640 * Pops a string from the stack, handling conversion if needed.
2641 * Check error with #xmlXPathCheckError.
2642 *
2643 * Returns the string
2644 */
2645xmlChar *
2646xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2647 xmlXPathObjectPtr obj;
2648 xmlChar * ret;
2649
2650 obj = valuePop(ctxt);
2651 if (obj == NULL) {
2652 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2653 return(NULL);
2654 }
William M. Brack08171912003-12-29 02:52:11 +00002655 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002656 /* TODO: needs refactoring somewhere else */
2657 if (obj->stringval == ret)
2658 obj->stringval = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002659 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002660 return(ret);
2661}
2662
2663/**
2664 * xmlXPathPopNodeSet:
2665 * @ctxt: an XPath parser context
2666 *
2667 * Pops a node-set from the stack, handling conversion if needed.
2668 * Check error with #xmlXPathCheckError.
2669 *
2670 * Returns the node-set
2671 */
2672xmlNodeSetPtr
2673xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2674 xmlXPathObjectPtr obj;
2675 xmlNodeSetPtr ret;
2676
Daniel Veillardf2a36f92004-11-08 17:55:01 +00002677 if (ctxt == NULL) return(NULL);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002678 if (ctxt->value == NULL) {
2679 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2680 return(NULL);
2681 }
2682 if (!xmlXPathStackIsNodeSet(ctxt)) {
2683 xmlXPathSetTypeError(ctxt);
2684 return(NULL);
2685 }
2686 obj = valuePop(ctxt);
2687 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00002688#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00002689 /* to fix memory leak of not clearing obj->user */
2690 if (obj->boolval && obj->user != NULL)
2691 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00002692#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002693 obj->nodesetval = NULL;
2694 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002695 return(ret);
2696}
2697
2698/**
2699 * xmlXPathPopExternal:
2700 * @ctxt: an XPath parser context
2701 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002702 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002703 * Check error with #xmlXPathCheckError.
2704 *
2705 * Returns the object
2706 */
2707void *
2708xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2709 xmlXPathObjectPtr obj;
2710 void * ret;
2711
Daniel Veillarda82b1822004-11-08 16:24:57 +00002712 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002713 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2714 return(NULL);
2715 }
2716 if (ctxt->value->type != XPATH_USERS) {
2717 xmlXPathSetTypeError(ctxt);
2718 return(NULL);
2719 }
2720 obj = valuePop(ctxt);
2721 ret = obj->user;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002722 obj->user = NULL;
2723 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002724 return(ret);
2725}
2726
Owen Taylor3473f882001-02-23 17:55:21 +00002727/*
2728 * Macros for accessing the content. Those should be used only by the parser,
2729 * and not exported.
2730 *
2731 * Dirty macros, i.e. one need to make assumption on the context to use them
2732 *
2733 * CUR_PTR return the current pointer to the xmlChar to be parsed.
2734 * CUR returns the current xmlChar value, i.e. a 8 bit value
2735 * in ISO-Latin or UTF-8.
2736 * This should be used internally by the parser
2737 * only to compare to ASCII values otherwise it would break when
2738 * running with UTF-8 encoding.
2739 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
2740 * to compare on ASCII based substring.
2741 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2742 * strings within the parser.
2743 * CURRENT Returns the current char value, with the full decoding of
2744 * UTF-8 if we are using this mode. It returns an int.
2745 * NEXT Skip to the next character, this does the proper decoding
2746 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
2747 * It returns the pointer to the current xmlChar.
2748 */
2749
2750#define CUR (*ctxt->cur)
2751#define SKIP(val) ctxt->cur += (val)
2752#define NXT(val) ctxt->cur[(val)]
2753#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00002754#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2755
2756#define COPY_BUF(l,b,i,v) \
2757 if (l == 1) b[i++] = (xmlChar) v; \
2758 else i += xmlCopyChar(l,&b[i],v)
2759
2760#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00002761
Daniel Veillard45490ae2008-07-29 09:13:19 +00002762#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00002763 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00002764
2765#define CURRENT (*ctxt->cur)
2766#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
2767
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002768
2769#ifndef DBL_DIG
2770#define DBL_DIG 16
2771#endif
2772#ifndef DBL_EPSILON
2773#define DBL_EPSILON 1E-9
2774#endif
2775
2776#define UPPER_DOUBLE 1E9
2777#define LOWER_DOUBLE 1E-5
William M. Brackca797882007-05-11 14:45:53 +00002778#define LOWER_DOUBLE_EXP 5
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002779
2780#define INTEGER_DIGITS DBL_DIG
William M. Brackca797882007-05-11 14:45:53 +00002781#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002782#define EXPONENT_DIGITS (3 + 2)
2783
2784/**
2785 * xmlXPathFormatNumber:
2786 * @number: number to format
2787 * @buffer: output buffer
2788 * @buffersize: size of output buffer
2789 *
2790 * Convert the number into a string representation.
2791 */
2792static void
2793xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2794{
Daniel Veillardcda96922001-08-21 10:56:31 +00002795 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002796 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00002797 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002798 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002799 break;
2800 case -1:
2801 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002802 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002803 break;
2804 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00002805 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002806 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002807 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00002808 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002809 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002810 } else if (number == ((int) number)) {
2811 char work[30];
2812 char *ptr, *cur;
Daniel Veillardb3d14912005-09-04 20:47:39 +00002813 int value = (int) number;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002814
2815 ptr = &buffer[0];
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002816 if (value == 0) {
2817 *ptr++ = '0';
2818 } else {
Daniel Veillardb3d14912005-09-04 20:47:39 +00002819 snprintf(work, 29, "%d", value);
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002820 cur = &work[0];
Daniel Veillardb3d14912005-09-04 20:47:39 +00002821 while ((*cur) && (ptr - buffer < buffersize)) {
2822 *ptr++ = *cur++;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002823 }
2824 }
2825 if (ptr - buffer < buffersize) {
2826 *ptr = 0;
2827 } else if (buffersize > 0) {
2828 ptr--;
2829 *ptr = 0;
2830 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002831 } else {
William M. Brackca797882007-05-11 14:45:53 +00002832 /*
2833 For the dimension of work,
2834 DBL_DIG is number of significant digits
2835 EXPONENT is only needed for "scientific notation"
2836 3 is sign, decimal point, and terminating zero
2837 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2838 Note that this dimension is slightly (a few characters)
2839 larger than actually necessary.
2840 */
2841 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
Bjorn Reese70a9da52001-04-21 16:57:29 +00002842 int integer_place, fraction_place;
2843 char *ptr;
2844 char *after_fraction;
2845 double absolute_value;
2846 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002847
Bjorn Reese70a9da52001-04-21 16:57:29 +00002848 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002849
Bjorn Reese70a9da52001-04-21 16:57:29 +00002850 /*
2851 * First choose format - scientific or regular floating point.
2852 * In either case, result is in work, and after_fraction points
2853 * just past the fractional part.
2854 */
2855 if ( ((absolute_value > UPPER_DOUBLE) ||
2856 (absolute_value < LOWER_DOUBLE)) &&
2857 (absolute_value != 0.0) ) {
2858 /* Use scientific notation */
2859 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2860 fraction_place = DBL_DIG - 1;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002861 size = snprintf(work, sizeof(work),"%*.*e",
Bjorn Reese70a9da52001-04-21 16:57:29 +00002862 integer_place, fraction_place, number);
Daniel Veillard11ce4002006-03-10 00:36:23 +00002863 while ((size > 0) && (work[size] != 'e')) size--;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002864
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002865 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002866 else {
2867 /* Use regular notation */
William M. Brackca797882007-05-11 14:45:53 +00002868 if (absolute_value > 0.0) {
2869 integer_place = (int)log10(absolute_value);
2870 if (integer_place > 0)
2871 fraction_place = DBL_DIG - integer_place - 1;
2872 else
2873 fraction_place = DBL_DIG - integer_place;
2874 } else {
2875 fraction_place = 1;
2876 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002877 size = snprintf(work, sizeof(work), "%0.*f",
2878 fraction_place, number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002879 }
2880
Bjorn Reese70a9da52001-04-21 16:57:29 +00002881 /* Remove fractional trailing zeroes */
William M. Brackca797882007-05-11 14:45:53 +00002882 after_fraction = work + size;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002883 ptr = after_fraction;
2884 while (*(--ptr) == '0')
2885 ;
2886 if (*ptr != '.')
2887 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002888 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002889
2890 /* Finally copy result back to caller */
2891 size = strlen(work) + 1;
2892 if (size > buffersize) {
2893 work[buffersize - 1] = 0;
2894 size = buffersize;
2895 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002896 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002897 }
2898 break;
2899 }
2900}
2901
Owen Taylor3473f882001-02-23 17:55:21 +00002902
2903/************************************************************************
2904 * *
2905 * Routines to handle NodeSets *
2906 * *
2907 ************************************************************************/
2908
2909/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002910 * xmlXPathOrderDocElems:
2911 * @doc: an input document
2912 *
2913 * Call this routine to speed up XPath computation on static documents.
2914 * This stamps all the element nodes with the document order
2915 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00002916 * field, the value stored is actually - the node number (starting at -1)
2917 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002918 *
William M. Brack08171912003-12-29 02:52:11 +00002919 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002920 * of error.
2921 */
2922long
2923xmlXPathOrderDocElems(xmlDocPtr doc) {
2924 long count = 0;
2925 xmlNodePtr cur;
2926
2927 if (doc == NULL)
2928 return(-1);
2929 cur = doc->children;
2930 while (cur != NULL) {
2931 if (cur->type == XML_ELEMENT_NODE) {
2932 cur->content = (void *) (-(++count));
2933 if (cur->children != NULL) {
2934 cur = cur->children;
2935 continue;
2936 }
2937 }
2938 if (cur->next != NULL) {
2939 cur = cur->next;
2940 continue;
2941 }
2942 do {
2943 cur = cur->parent;
2944 if (cur == NULL)
2945 break;
2946 if (cur == (xmlNodePtr) doc) {
2947 cur = NULL;
2948 break;
2949 }
2950 if (cur->next != NULL) {
2951 cur = cur->next;
2952 break;
2953 }
2954 } while (cur != NULL);
2955 }
2956 return(count);
2957}
2958
2959/**
Owen Taylor3473f882001-02-23 17:55:21 +00002960 * xmlXPathCmpNodes:
2961 * @node1: the first node
2962 * @node2: the second node
2963 *
2964 * Compare two nodes w.r.t document order
2965 *
2966 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00002967 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00002968 */
2969int
2970xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2971 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002972 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002973 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002974 xmlNodePtr cur, root;
2975
2976 if ((node1 == NULL) || (node2 == NULL))
2977 return(-2);
2978 /*
2979 * a couple of optimizations which will avoid computations in most cases
2980 */
William M. Brackee0b9822007-03-07 08:15:01 +00002981 if (node1 == node2) /* trivial case */
2982 return(0);
Daniel Veillardedfd5882003-03-07 14:20:40 +00002983 if (node1->type == XML_ATTRIBUTE_NODE) {
2984 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002985 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002986 node1 = node1->parent;
2987 }
2988 if (node2->type == XML_ATTRIBUTE_NODE) {
2989 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002990 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002991 node2 = node2->parent;
2992 }
2993 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00002994 if (attr1 == attr2) {
2995 /* not required, but we keep attributes in order */
2996 if (attr1 != 0) {
2997 cur = attrNode2->prev;
2998 while (cur != NULL) {
2999 if (cur == attrNode1)
3000 return (1);
3001 cur = cur->prev;
3002 }
3003 return (-1);
3004 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00003005 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00003006 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00003007 if (attr2 == 1)
3008 return(1);
3009 return(-1);
3010 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00003011 if ((node1->type == XML_NAMESPACE_DECL) ||
3012 (node2->type == XML_NAMESPACE_DECL))
3013 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00003014 if (node1 == node2->prev)
3015 return(1);
3016 if (node1 == node2->next)
3017 return(-1);
3018
3019 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003020 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00003021 */
3022 if ((node1->type == XML_ELEMENT_NODE) &&
3023 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003024 (0 > (long) node1->content) &&
3025 (0 > (long) node2->content) &&
3026 (node1->doc == node2->doc)) {
3027 long l1, l2;
3028
3029 l1 = -((long) node1->content);
3030 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00003031 if (l1 < l2)
3032 return(1);
3033 if (l1 > l2)
3034 return(-1);
3035 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00003036
Daniel Veillard7216cfd2002-11-08 15:10:00 +00003037 /*
Owen Taylor3473f882001-02-23 17:55:21 +00003038 * compute depth to root
3039 */
3040 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3041 if (cur == node1)
3042 return(1);
3043 depth2++;
3044 }
3045 root = cur;
3046 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3047 if (cur == node2)
3048 return(-1);
3049 depth1++;
3050 }
3051 /*
3052 * Distinct document (or distinct entities :-( ) case.
3053 */
3054 if (root != cur) {
3055 return(-2);
3056 }
3057 /*
3058 * get the nearest common ancestor.
3059 */
3060 while (depth1 > depth2) {
3061 depth1--;
3062 node1 = node1->parent;
3063 }
3064 while (depth2 > depth1) {
3065 depth2--;
3066 node2 = node2->parent;
3067 }
3068 while (node1->parent != node2->parent) {
3069 node1 = node1->parent;
3070 node2 = node2->parent;
3071 /* should not happen but just in case ... */
3072 if ((node1 == NULL) || (node2 == NULL))
3073 return(-2);
3074 }
3075 /*
3076 * Find who's first.
3077 */
Daniel Veillardf49be472004-02-17 11:48:18 +00003078 if (node1 == node2->prev)
3079 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00003080 if (node1 == node2->next)
3081 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00003082 /*
3083 * Speedup using document order if availble.
3084 */
3085 if ((node1->type == XML_ELEMENT_NODE) &&
3086 (node2->type == XML_ELEMENT_NODE) &&
3087 (0 > (long) node1->content) &&
3088 (0 > (long) node2->content) &&
3089 (node1->doc == node2->doc)) {
3090 long l1, l2;
3091
3092 l1 = -((long) node1->content);
3093 l2 = -((long) node2->content);
3094 if (l1 < l2)
3095 return(1);
3096 if (l1 > l2)
3097 return(-1);
3098 }
3099
Owen Taylor3473f882001-02-23 17:55:21 +00003100 for (cur = node1->next;cur != NULL;cur = cur->next)
3101 if (cur == node2)
3102 return(1);
3103 return(-1); /* assume there is no sibling list corruption */
3104}
3105
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003106#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003107/**
3108 * xmlXPathCmpNodesExt:
3109 * @node1: the first node
3110 * @node2: the second node
3111 *
3112 * Compare two nodes w.r.t document order.
3113 * This one is optimized for handling of non-element nodes.
3114 *
3115 * Returns -2 in case of error 1 if first point < second point, 0 if
3116 * it's the same node, -1 otherwise
3117 */
3118static int
3119xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
3120 int depth1, depth2;
3121 int misc = 0, precedence1 = 0, precedence2 = 0;
3122 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
3123 xmlNodePtr cur, root;
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003124 long l1, l2;
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003125
3126 if ((node1 == NULL) || (node2 == NULL))
3127 return(-2);
3128
3129 if (node1 == node2)
3130 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00003131
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003132 /*
3133 * a couple of optimizations which will avoid computations in most cases
Daniel Veillard45490ae2008-07-29 09:13:19 +00003134 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003135 switch (node1->type) {
3136 case XML_ELEMENT_NODE:
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003137 if (node2->type == XML_ELEMENT_NODE) {
3138 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
3139 (0 > (long) node2->content) &&
3140 (node1->doc == node2->doc))
Daniel Veillard45490ae2008-07-29 09:13:19 +00003141 {
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003142 l1 = -((long) node1->content);
3143 l2 = -((long) node2->content);
3144 if (l1 < l2)
3145 return(1);
3146 if (l1 > l2)
3147 return(-1);
3148 } else
Daniel Veillard45490ae2008-07-29 09:13:19 +00003149 goto turtle_comparison;
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003150 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003151 break;
3152 case XML_ATTRIBUTE_NODE:
3153 precedence1 = 1; /* element is owner */
3154 miscNode1 = node1;
3155 node1 = node1->parent;
3156 misc = 1;
3157 break;
3158 case XML_TEXT_NODE:
3159 case XML_CDATA_SECTION_NODE:
3160 case XML_COMMENT_NODE:
3161 case XML_PI_NODE: {
3162 miscNode1 = node1;
3163 /*
3164 * Find nearest element node.
Daniel Veillard45490ae2008-07-29 09:13:19 +00003165 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003166 if (node1->prev != NULL) {
3167 do {
3168 node1 = node1->prev;
3169 if (node1->type == XML_ELEMENT_NODE) {
3170 precedence1 = 3; /* element in prev-sibl axis */
3171 break;
3172 }
3173 if (node1->prev == NULL) {
3174 precedence1 = 2; /* element is parent */
3175 /*
3176 * URGENT TODO: Are there any cases, where the
3177 * parent of such a node is not an element node?
3178 */
3179 node1 = node1->parent;
3180 break;
3181 }
3182 } while (1);
3183 } else {
3184 precedence1 = 2; /* element is parent */
3185 node1 = node1->parent;
3186 }
William M. Brack31700e62007-06-13 20:33:02 +00003187 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
3188 (0 <= (long) node1->content)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003189 /*
3190 * Fallback for whatever case.
3191 */
3192 node1 = miscNode1;
3193 precedence1 = 0;
3194 } else
3195 misc = 1;
3196 }
3197 break;
3198 case XML_NAMESPACE_DECL:
3199 /*
3200 * TODO: why do we return 1 for namespace nodes?
3201 */
3202 return(1);
3203 default:
3204 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00003205 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003206 switch (node2->type) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00003207 case XML_ELEMENT_NODE:
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003208 break;
3209 case XML_ATTRIBUTE_NODE:
3210 precedence2 = 1; /* element is owner */
3211 miscNode2 = node2;
3212 node2 = node2->parent;
3213 misc = 1;
3214 break;
3215 case XML_TEXT_NODE:
3216 case XML_CDATA_SECTION_NODE:
3217 case XML_COMMENT_NODE:
3218 case XML_PI_NODE: {
3219 miscNode2 = node2;
3220 if (node2->prev != NULL) {
3221 do {
3222 node2 = node2->prev;
3223 if (node2->type == XML_ELEMENT_NODE) {
3224 precedence2 = 3; /* element in prev-sibl axis */
3225 break;
3226 }
3227 if (node2->prev == NULL) {
3228 precedence2 = 2; /* element is parent */
3229 node2 = node2->parent;
3230 break;
3231 }
3232 } while (1);
3233 } else {
3234 precedence2 = 2; /* element is parent */
3235 node2 = node2->parent;
Daniel Veillard45490ae2008-07-29 09:13:19 +00003236 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003237 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3238 (0 <= (long) node1->content))
3239 {
3240 node2 = miscNode2;
3241 precedence2 = 0;
3242 } else
3243 misc = 1;
3244 }
3245 break;
3246 case XML_NAMESPACE_DECL:
3247 return(1);
3248 default:
3249 break;
3250 }
3251 if (misc) {
3252 if (node1 == node2) {
3253 if (precedence1 == precedence2) {
3254 /*
3255 * The ugly case; but normally there aren't many
3256 * adjacent non-element nodes around.
3257 */
3258 cur = miscNode2->prev;
3259 while (cur != NULL) {
3260 if (cur == miscNode1)
3261 return(1);
3262 if (cur->type == XML_ELEMENT_NODE)
3263 return(-1);
3264 cur = cur->prev;
3265 }
3266 return (-1);
3267 } else {
3268 /*
3269 * Evaluate based on higher precedence wrt to the element.
3270 * TODO: This assumes attributes are sorted before content.
3271 * Is this 100% correct?
3272 */
3273 if (precedence1 < precedence2)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003274 return(1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003275 else
Daniel Veillard45490ae2008-07-29 09:13:19 +00003276 return(-1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003277 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00003278 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003279 /*
3280 * Special case: One of the helper-elements is contained by the other.
3281 * <foo>
3282 * <node2>
3283 * <node1>Text-1(precedence1 == 2)</node1>
3284 * </node2>
3285 * Text-6(precedence2 == 3)
3286 * </foo>
Daniel Veillard45490ae2008-07-29 09:13:19 +00003287 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003288 if ((precedence2 == 3) && (precedence1 > 1)) {
3289 cur = node1->parent;
3290 while (cur) {
3291 if (cur == node2)
3292 return(1);
3293 cur = cur->parent;
3294 }
3295 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00003296 if ((precedence1 == 3) && (precedence2 > 1)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003297 cur = node2->parent;
3298 while (cur) {
3299 if (cur == node1)
3300 return(-1);
3301 cur = cur->parent;
3302 }
3303 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00003304 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003305
3306 /*
3307 * Speedup using document order if availble.
3308 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00003309 if ((node1->type == XML_ELEMENT_NODE) &&
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003310 (node2->type == XML_ELEMENT_NODE) &&
3311 (0 > (long) node1->content) &&
3312 (0 > (long) node2->content) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +00003313 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003314
3315 l1 = -((long) node1->content);
3316 l2 = -((long) node2->content);
3317 if (l1 < l2)
3318 return(1);
3319 if (l1 > l2)
3320 return(-1);
3321 }
3322
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003323turtle_comparison:
3324
3325 if (node1 == node2->prev)
3326 return(1);
3327 if (node1 == node2->next)
3328 return(-1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003329 /*
3330 * compute depth to root
3331 */
3332 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3333 if (cur == node1)
3334 return(1);
3335 depth2++;
3336 }
3337 root = cur;
3338 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3339 if (cur == node2)
3340 return(-1);
3341 depth1++;
3342 }
3343 /*
3344 * Distinct document (or distinct entities :-( ) case.
3345 */
3346 if (root != cur) {
3347 return(-2);
3348 }
3349 /*
3350 * get the nearest common ancestor.
3351 */
3352 while (depth1 > depth2) {
3353 depth1--;
3354 node1 = node1->parent;
3355 }
3356 while (depth2 > depth1) {
3357 depth2--;
3358 node2 = node2->parent;
3359 }
3360 while (node1->parent != node2->parent) {
3361 node1 = node1->parent;
3362 node2 = node2->parent;
3363 /* should not happen but just in case ... */
3364 if ((node1 == NULL) || (node2 == NULL))
3365 return(-2);
3366 }
3367 /*
3368 * Find who's first.
3369 */
3370 if (node1 == node2->prev)
3371 return(1);
3372 if (node1 == node2->next)
3373 return(-1);
3374 /*
3375 * Speedup using document order if availble.
3376 */
3377 if ((node1->type == XML_ELEMENT_NODE) &&
3378 (node2->type == XML_ELEMENT_NODE) &&
3379 (0 > (long) node1->content) &&
3380 (0 > (long) node2->content) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +00003381 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003382
3383 l1 = -((long) node1->content);
3384 l2 = -((long) node2->content);
3385 if (l1 < l2)
3386 return(1);
3387 if (l1 > l2)
3388 return(-1);
3389 }
3390
3391 for (cur = node1->next;cur != NULL;cur = cur->next)
3392 if (cur == node2)
3393 return(1);
3394 return(-1); /* assume there is no sibling list corruption */
3395}
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003396#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003397
Owen Taylor3473f882001-02-23 17:55:21 +00003398/**
3399 * xmlXPathNodeSetSort:
3400 * @set: the node set
3401 *
3402 * Sort the node set in document order
3403 */
3404void
3405xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Vojtech Fried3e031b72012-08-24 16:52:44 +08003406#ifndef WITH_TIM_SORT
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003407 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003408 xmlNodePtr tmp;
Vojtech Fried3e031b72012-08-24 16:52:44 +08003409#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003410
3411 if (set == NULL)
3412 return;
3413
Vojtech Fried3e031b72012-08-24 16:52:44 +08003414#ifndef WITH_TIM_SORT
3415 /*
3416 * Use the old Shell's sort implementation to sort the node-set
3417 * Timsort ought to be quite faster
3418 */
Owen Taylor3473f882001-02-23 17:55:21 +00003419 len = set->nodeNr;
3420 for (incr = len / 2; incr > 0; incr /= 2) {
3421 for (i = incr; i < len; i++) {
3422 j = i - incr;
3423 while (j >= 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003424#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003425 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3426 set->nodeTab[j + incr]) == -1)
3427#else
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003428 if (xmlXPathCmpNodes(set->nodeTab[j],
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003429 set->nodeTab[j + incr]) == -1)
3430#endif
3431 {
Owen Taylor3473f882001-02-23 17:55:21 +00003432 tmp = set->nodeTab[j];
3433 set->nodeTab[j] = set->nodeTab[j + incr];
3434 set->nodeTab[j + incr] = tmp;
3435 j -= incr;
3436 } else
3437 break;
3438 }
3439 }
3440 }
Vojtech Fried3e031b72012-08-24 16:52:44 +08003441#else /* WITH_TIM_SORT */
3442 libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3443#endif /* WITH_TIM_SORT */
Owen Taylor3473f882001-02-23 17:55:21 +00003444}
3445
3446#define XML_NODESET_DEFAULT 10
3447/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003448 * xmlXPathNodeSetDupNs:
3449 * @node: the parent node of the namespace XPath node
3450 * @ns: the libxml namespace declaration node.
3451 *
3452 * Namespace node in libxml don't match the XPath semantic. In a node set
3453 * the namespace nodes are duplicated and the next pointer is set to the
3454 * parent node in the XPath semantic.
3455 *
3456 * Returns the newly created object.
3457 */
3458static xmlNodePtr
3459xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3460 xmlNsPtr cur;
3461
3462 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3463 return(NULL);
3464 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3465 return((xmlNodePtr) ns);
3466
3467 /*
3468 * Allocate a new Namespace and fill the fields.
3469 */
3470 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3471 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003472 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003473 return(NULL);
3474 }
3475 memset(cur, 0, sizeof(xmlNs));
3476 cur->type = XML_NAMESPACE_DECL;
3477 if (ns->href != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003478 cur->href = xmlStrdup(ns->href);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003479 if (ns->prefix != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003480 cur->prefix = xmlStrdup(ns->prefix);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003481 cur->next = (xmlNsPtr) node;
3482 return((xmlNodePtr) cur);
3483}
3484
3485/**
3486 * xmlXPathNodeSetFreeNs:
3487 * @ns: the XPath namespace node found in a nodeset.
3488 *
William M. Brack08171912003-12-29 02:52:11 +00003489 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003490 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00003491 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003492 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00003493void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003494xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3495 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3496 return;
3497
3498 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3499 if (ns->href != NULL)
3500 xmlFree((xmlChar *)ns->href);
3501 if (ns->prefix != NULL)
3502 xmlFree((xmlChar *)ns->prefix);
3503 xmlFree(ns);
3504 }
3505}
3506
3507/**
Owen Taylor3473f882001-02-23 17:55:21 +00003508 * xmlXPathNodeSetCreate:
3509 * @val: an initial xmlNodePtr, or NULL
3510 *
3511 * Create a new xmlNodeSetPtr of type double and of value @val
3512 *
3513 * Returns the newly created object.
3514 */
3515xmlNodeSetPtr
3516xmlXPathNodeSetCreate(xmlNodePtr val) {
3517 xmlNodeSetPtr ret;
3518
3519 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3520 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003521 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003522 return(NULL);
3523 }
3524 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3525 if (val != NULL) {
3526 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3527 sizeof(xmlNodePtr));
3528 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003529 xmlXPathErrMemory(NULL, "creating nodeset\n");
3530 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003531 return(NULL);
3532 }
3533 memset(ret->nodeTab, 0 ,
3534 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3535 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003536 if (val->type == XML_NAMESPACE_DECL) {
3537 xmlNsPtr ns = (xmlNsPtr) val;
3538
3539 ret->nodeTab[ret->nodeNr++] =
3540 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3541 } else
3542 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003543 }
3544 return(ret);
3545}
3546
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003547/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003548 * xmlXPathNodeSetCreateSize:
3549 * @size: the initial size of the set
3550 *
3551 * Create a new xmlNodeSetPtr of type double and of value @val
3552 *
3553 * Returns the newly created object.
3554 */
3555static xmlNodeSetPtr
3556xmlXPathNodeSetCreateSize(int size) {
3557 xmlNodeSetPtr ret;
3558
3559 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3560 if (ret == NULL) {
3561 xmlXPathErrMemory(NULL, "creating nodeset\n");
3562 return(NULL);
3563 }
3564 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3565 if (size < XML_NODESET_DEFAULT)
3566 size = XML_NODESET_DEFAULT;
3567 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3568 if (ret->nodeTab == NULL) {
3569 xmlXPathErrMemory(NULL, "creating nodeset\n");
3570 xmlFree(ret);
3571 return(NULL);
3572 }
3573 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
Daniel Veillard45490ae2008-07-29 09:13:19 +00003574 ret->nodeMax = size;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003575 return(ret);
3576}
3577
3578/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003579 * xmlXPathNodeSetContains:
3580 * @cur: the node-set
3581 * @val: the node
3582 *
3583 * checks whether @cur contains @val
3584 *
3585 * Returns true (1) if @cur contains @val, false (0) otherwise
3586 */
3587int
3588xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3589 int i;
3590
Daniel Veillarda82b1822004-11-08 16:24:57 +00003591 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003592 if (val->type == XML_NAMESPACE_DECL) {
3593 for (i = 0; i < cur->nodeNr; i++) {
3594 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3595 xmlNsPtr ns1, ns2;
3596
3597 ns1 = (xmlNsPtr) val;
3598 ns2 = (xmlNsPtr) cur->nodeTab[i];
3599 if (ns1 == ns2)
3600 return(1);
3601 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3602 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3603 return(1);
3604 }
3605 }
3606 } else {
3607 for (i = 0; i < cur->nodeNr; i++) {
3608 if (cur->nodeTab[i] == val)
3609 return(1);
3610 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003611 }
3612 return(0);
3613}
3614
3615/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003616 * xmlXPathNodeSetAddNs:
3617 * @cur: the initial node set
3618 * @node: the hosting node
3619 * @ns: a the namespace node
3620 *
3621 * add a new namespace node to an existing NodeSet
3622 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00003623void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003624xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3625 int i;
3626
Daniel Veillard45490ae2008-07-29 09:13:19 +00003627
Daniel Veillarda82b1822004-11-08 16:24:57 +00003628 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3629 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003630 (node->type != XML_ELEMENT_NODE))
3631 return;
3632
William M. Brack08171912003-12-29 02:52:11 +00003633 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003634 /*
William M. Brack08171912003-12-29 02:52:11 +00003635 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003636 */
3637 for (i = 0;i < cur->nodeNr;i++) {
3638 if ((cur->nodeTab[i] != NULL) &&
3639 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00003640 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003641 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3642 return;
3643 }
3644
3645 /*
3646 * grow the nodeTab if needed
3647 */
3648 if (cur->nodeMax == 0) {
3649 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3650 sizeof(xmlNodePtr));
3651 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003652 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003653 return;
3654 }
3655 memset(cur->nodeTab, 0 ,
3656 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3657 cur->nodeMax = XML_NODESET_DEFAULT;
3658 } else if (cur->nodeNr == cur->nodeMax) {
3659 xmlNodePtr *temp;
3660
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003661 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3662 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3663 return;
3664 }
Chris Evansd7958b22011-03-23 08:13:06 +08003665 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003666 sizeof(xmlNodePtr));
3667 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003668 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003669 return;
3670 }
Chris Evansd7958b22011-03-23 08:13:06 +08003671 cur->nodeMax *= 2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003672 cur->nodeTab = temp;
3673 }
3674 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3675}
3676
3677/**
Owen Taylor3473f882001-02-23 17:55:21 +00003678 * xmlXPathNodeSetAdd:
3679 * @cur: the initial node set
3680 * @val: a new xmlNodePtr
3681 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003682 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00003683 */
3684void
3685xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3686 int i;
3687
Daniel Veillarda82b1822004-11-08 16:24:57 +00003688 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003689
William M. Brack08171912003-12-29 02:52:11 +00003690 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003691 /*
William M. Brack08171912003-12-29 02:52:11 +00003692 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00003693 */
3694 for (i = 0;i < cur->nodeNr;i++)
3695 if (cur->nodeTab[i] == val) return;
3696
3697 /*
3698 * grow the nodeTab if needed
3699 */
3700 if (cur->nodeMax == 0) {
3701 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3702 sizeof(xmlNodePtr));
3703 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003704 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003705 return;
3706 }
3707 memset(cur->nodeTab, 0 ,
3708 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3709 cur->nodeMax = XML_NODESET_DEFAULT;
3710 } else if (cur->nodeNr == cur->nodeMax) {
3711 xmlNodePtr *temp;
3712
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003713 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3714 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3715 return;
3716 }
Daniel Veillard0cbeb502010-11-15 12:06:29 +01003717 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003718 sizeof(xmlNodePtr));
3719 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003720 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003721 return;
3722 }
Daniel Veillard0cbeb502010-11-15 12:06:29 +01003723 cur->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003724 cur->nodeTab = temp;
3725 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003726 if (val->type == XML_NAMESPACE_DECL) {
3727 xmlNsPtr ns = (xmlNsPtr) val;
3728
Daniel Veillard45490ae2008-07-29 09:13:19 +00003729 cur->nodeTab[cur->nodeNr++] =
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003730 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3731 } else
3732 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003733}
3734
3735/**
3736 * xmlXPathNodeSetAddUnique:
3737 * @cur: the initial node set
3738 * @val: a new xmlNodePtr
3739 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003740 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00003741 * when we are sure the node is not already in the set.
3742 */
3743void
3744xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00003745 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003746
William M. Brack08171912003-12-29 02:52:11 +00003747 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003748 /*
3749 * grow the nodeTab if needed
3750 */
3751 if (cur->nodeMax == 0) {
3752 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3753 sizeof(xmlNodePtr));
3754 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003755 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003756 return;
3757 }
3758 memset(cur->nodeTab, 0 ,
3759 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3760 cur->nodeMax = XML_NODESET_DEFAULT;
3761 } else if (cur->nodeNr == cur->nodeMax) {
3762 xmlNodePtr *temp;
3763
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003764 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3765 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3766 return;
3767 }
Chris Evansd7958b22011-03-23 08:13:06 +08003768 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003769 sizeof(xmlNodePtr));
3770 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003771 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003772 return;
3773 }
3774 cur->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08003775 cur->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003776 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003777 if (val->type == XML_NAMESPACE_DECL) {
3778 xmlNsPtr ns = (xmlNsPtr) val;
3779
Daniel Veillard45490ae2008-07-29 09:13:19 +00003780 cur->nodeTab[cur->nodeNr++] =
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003781 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3782 } else
3783 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003784}
3785
3786/**
3787 * xmlXPathNodeSetMerge:
3788 * @val1: the first NodeSet or NULL
3789 * @val2: the second NodeSet
3790 *
3791 * Merges two nodesets, all nodes from @val2 are added to @val1
3792 * if @val1 is NULL, a new set is created and copied from @val2
3793 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003794 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003795 */
3796xmlNodeSetPtr
3797xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003798 int i, j, initNr, skip;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003799 xmlNodePtr n1, n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003800
3801 if (val2 == NULL) return(val1);
3802 if (val1 == NULL) {
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003803 val1 = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00003804 if (val1 == NULL)
3805 return (NULL);
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003806#if 0
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003807 /*
3808 * TODO: The optimization won't work in every case, since
3809 * those nasty namespace nodes need to be added with
3810 * xmlXPathNodeSetDupNs() to the set; thus a pure
3811 * memcpy is not possible.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00003812 * If there was a flag on the nodesetval, indicating that
3813 * some temporary nodes are in, that would be helpfull.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003814 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00003815 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003816 * Optimization: Create an equally sized node-set
3817 * and memcpy the content.
3818 */
3819 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3820 if (val1 == NULL)
3821 return(NULL);
3822 if (val2->nodeNr != 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003823 if (val2->nodeNr == 1)
3824 *(val1->nodeTab) = *(val2->nodeTab);
3825 else {
3826 memcpy(val1->nodeTab, val2->nodeTab,
3827 val2->nodeNr * sizeof(xmlNodePtr));
3828 }
3829 val1->nodeNr = val2->nodeNr;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003830 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003831 return(val1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003832#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003833 }
3834
William M. Brack08171912003-12-29 02:52:11 +00003835 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003836 initNr = val1->nodeNr;
3837
3838 for (i = 0;i < val2->nodeNr;i++) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00003839 n2 = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00003840 /*
William M. Brack08171912003-12-29 02:52:11 +00003841 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003842 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003843 skip = 0;
3844 for (j = 0; j < initNr; j++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003845 n1 = val1->nodeTab[j];
3846 if (n1 == n2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003847 skip = 1;
3848 break;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003849 } else if ((n1->type == XML_NAMESPACE_DECL) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +00003850 (n2->type == XML_NAMESPACE_DECL)) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003851 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3852 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3853 ((xmlNsPtr) n2)->prefix)))
3854 {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003855 skip = 1;
3856 break;
3857 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003858 }
3859 }
3860 if (skip)
3861 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00003862
3863 /*
3864 * grow the nodeTab if needed
3865 */
3866 if (val1->nodeMax == 0) {
3867 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3868 sizeof(xmlNodePtr));
3869 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003870 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003871 return(NULL);
3872 }
3873 memset(val1->nodeTab, 0 ,
3874 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3875 val1->nodeMax = XML_NODESET_DEFAULT;
3876 } else if (val1->nodeNr == val1->nodeMax) {
3877 xmlNodePtr *temp;
3878
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003879 if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3880 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3881 return(NULL);
3882 }
Chris Evansd7958b22011-03-23 08:13:06 +08003883 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003884 sizeof(xmlNodePtr));
3885 if (temp == 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 val1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08003890 val1->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003891 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003892 if (n2->type == XML_NAMESPACE_DECL) {
3893 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003894
3895 val1->nodeTab[val1->nodeNr++] =
3896 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3897 } else
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003898 val1->nodeTab[val1->nodeNr++] = n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003899 }
3900
3901 return(val1);
3902}
3903
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003904
3905/**
3906 * xmlXPathNodeSetMergeAndClear:
3907 * @set1: the first NodeSet or NULL
3908 * @set2: the second NodeSet
3909 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3910 *
3911 * Merges two nodesets, all nodes from @set2 are added to @set1
3912 * if @set1 is NULL, a new set is created and copied from @set2.
3913 * Checks for duplicate nodes. Clears set2.
3914 *
3915 * Returns @set1 once extended or NULL in case of error.
3916 */
3917static xmlNodeSetPtr
3918xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3919 int hasNullEntries)
3920{
3921 if ((set1 == NULL) && (hasNullEntries == 0)) {
3922 /*
3923 * Note that doing a memcpy of the list, namespace nodes are
3924 * just assigned to set1, since set2 is cleared anyway.
3925 */
3926 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3927 if (set1 == NULL)
3928 return(NULL);
3929 if (set2->nodeNr != 0) {
3930 memcpy(set1->nodeTab, set2->nodeTab,
3931 set2->nodeNr * sizeof(xmlNodePtr));
3932 set1->nodeNr = set2->nodeNr;
3933 }
3934 } else {
3935 int i, j, initNbSet1;
3936 xmlNodePtr n1, n2;
3937
3938 if (set1 == NULL)
Daniel Veillardf88d8492008-04-01 08:00:31 +00003939 set1 = xmlXPathNodeSetCreate(NULL);
3940 if (set1 == NULL)
3941 return (NULL);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003942
Daniel Veillard45490ae2008-07-29 09:13:19 +00003943 initNbSet1 = set1->nodeNr;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003944 for (i = 0;i < set2->nodeNr;i++) {
3945 n2 = set2->nodeTab[i];
3946 /*
3947 * Skip NULLed entries.
3948 */
3949 if (n2 == NULL)
3950 continue;
3951 /*
3952 * Skip duplicates.
3953 */
3954 for (j = 0; j < initNbSet1; j++) {
3955 n1 = set1->nodeTab[j];
Daniel Veillard45490ae2008-07-29 09:13:19 +00003956 if (n1 == n2) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003957 goto skip_node;
3958 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3959 (n2->type == XML_NAMESPACE_DECL))
Daniel Veillard45490ae2008-07-29 09:13:19 +00003960 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003961 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3962 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3963 ((xmlNsPtr) n2)->prefix)))
3964 {
3965 /*
3966 * Free the namespace node.
3967 */
3968 set2->nodeTab[i] = NULL;
3969 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3970 goto skip_node;
3971 }
3972 }
3973 }
3974 /*
3975 * grow the nodeTab if needed
3976 */
3977 if (set1->nodeMax == 0) {
3978 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3979 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3980 if (set1->nodeTab == NULL) {
3981 xmlXPathErrMemory(NULL, "merging nodeset\n");
3982 return(NULL);
3983 }
3984 memset(set1->nodeTab, 0,
3985 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3986 set1->nodeMax = XML_NODESET_DEFAULT;
3987 } else if (set1->nodeNr >= set1->nodeMax) {
3988 xmlNodePtr *temp;
Daniel Veillard45490ae2008-07-29 09:13:19 +00003989
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003990 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3991 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3992 return(NULL);
3993 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003994 temp = (xmlNodePtr *) xmlRealloc(
Chris Evansd7958b22011-03-23 08:13:06 +08003995 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003996 if (temp == NULL) {
3997 xmlXPathErrMemory(NULL, "merging nodeset\n");
3998 return(NULL);
3999 }
4000 set1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08004001 set1->nodeMax *= 2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004002 }
4003 if (n2->type == XML_NAMESPACE_DECL) {
4004 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004005
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004006 set1->nodeTab[set1->nodeNr++] =
4007 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
4008 } else
4009 set1->nodeTab[set1->nodeNr++] = n2;
4010skip_node:
4011 {}
4012 }
4013 }
4014 set2->nodeNr = 0;
4015 return(set1);
4016}
4017
4018/**
4019 * xmlXPathNodeSetMergeAndClearNoDupls:
4020 * @set1: the first NodeSet or NULL
4021 * @set2: the second NodeSet
4022 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
4023 *
4024 * Merges two nodesets, all nodes from @set2 are added to @set1
4025 * if @set1 is NULL, a new set is created and copied from @set2.
4026 * Doesn't chack for duplicate nodes. Clears set2.
4027 *
4028 * Returns @set1 once extended or NULL in case of error.
4029 */
4030static xmlNodeSetPtr
4031xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
4032 int hasNullEntries)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004033{
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004034 if (set2 == NULL)
4035 return(set1);
4036 if ((set1 == NULL) && (hasNullEntries == 0)) {
4037 /*
4038 * Note that doing a memcpy of the list, namespace nodes are
4039 * just assigned to set1, since set2 is cleared anyway.
4040 */
4041 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
4042 if (set1 == NULL)
4043 return(NULL);
4044 if (set2->nodeNr != 0) {
4045 memcpy(set1->nodeTab, set2->nodeTab,
4046 set2->nodeNr * sizeof(xmlNodePtr));
4047 set1->nodeNr = set2->nodeNr;
4048 }
4049 } else {
4050 int i;
4051 xmlNodePtr n2;
4052
4053 if (set1 == NULL)
4054 set1 = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004055 if (set1 == NULL)
4056 return (NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004057
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004058 for (i = 0;i < set2->nodeNr;i++) {
4059 n2 = set2->nodeTab[i];
4060 /*
4061 * Skip NULLed entries.
4062 */
4063 if (n2 == NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004064 continue;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004065 if (set1->nodeMax == 0) {
4066 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4067 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4068 if (set1->nodeTab == NULL) {
4069 xmlXPathErrMemory(NULL, "merging nodeset\n");
4070 return(NULL);
4071 }
4072 memset(set1->nodeTab, 0,
4073 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4074 set1->nodeMax = XML_NODESET_DEFAULT;
4075 } else if (set1->nodeNr >= set1->nodeMax) {
4076 xmlNodePtr *temp;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004077
Daniel Veillardcd852ad2012-07-30 10:12:18 +08004078 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4079 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4080 return(NULL);
4081 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004082 temp = (xmlNodePtr *) xmlRealloc(
Chris Evansd7958b22011-03-23 08:13:06 +08004083 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004084 if (temp == NULL) {
4085 xmlXPathErrMemory(NULL, "merging nodeset\n");
4086 return(NULL);
4087 }
4088 set1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08004089 set1->nodeMax *= 2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004090 }
4091 set1->nodeTab[set1->nodeNr++] = n2;
4092 }
4093 }
4094 set2->nodeNr = 0;
4095 return(set1);
4096}
Daniel Veillard75be0132002-03-13 10:03:35 +00004097
4098/**
Owen Taylor3473f882001-02-23 17:55:21 +00004099 * xmlXPathNodeSetDel:
4100 * @cur: the initial node set
4101 * @val: an xmlNodePtr
4102 *
4103 * Removes an xmlNodePtr from an existing NodeSet
4104 */
4105void
4106xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4107 int i;
4108
4109 if (cur == NULL) return;
4110 if (val == NULL) return;
4111
4112 /*
William M. Brack08171912003-12-29 02:52:11 +00004113 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00004114 */
4115 for (i = 0;i < cur->nodeNr;i++)
4116 if (cur->nodeTab[i] == val) break;
4117
William M. Brack08171912003-12-29 02:52:11 +00004118 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00004119#ifdef DEBUG
Daniel Veillard45490ae2008-07-29 09:13:19 +00004120 xmlGenericError(xmlGenericErrorContext,
Owen Taylor3473f882001-02-23 17:55:21 +00004121 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4122 val->name);
4123#endif
4124 return;
4125 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004126 if ((cur->nodeTab[i] != NULL) &&
4127 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4128 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004129 cur->nodeNr--;
4130 for (;i < cur->nodeNr;i++)
4131 cur->nodeTab[i] = cur->nodeTab[i + 1];
4132 cur->nodeTab[cur->nodeNr] = NULL;
4133}
4134
4135/**
4136 * xmlXPathNodeSetRemove:
4137 * @cur: the initial node set
4138 * @val: the index to remove
4139 *
4140 * Removes an entry from an existing NodeSet list.
4141 */
4142void
4143xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4144 if (cur == NULL) return;
4145 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004146 if ((cur->nodeTab[val] != NULL) &&
4147 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4148 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00004149 cur->nodeNr--;
4150 for (;val < cur->nodeNr;val++)
4151 cur->nodeTab[val] = cur->nodeTab[val + 1];
4152 cur->nodeTab[cur->nodeNr] = NULL;
4153}
4154
4155/**
4156 * xmlXPathFreeNodeSet:
4157 * @obj: the xmlNodeSetPtr to free
4158 *
4159 * Free the NodeSet compound (not the actual nodes !).
4160 */
4161void
4162xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4163 if (obj == NULL) return;
4164 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004165 int i;
4166
William M. Brack08171912003-12-29 02:52:11 +00004167 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004168 for (i = 0;i < obj->nodeNr;i++)
4169 if ((obj->nodeTab[i] != NULL) &&
4170 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4171 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004172 xmlFree(obj->nodeTab);
4173 }
Owen Taylor3473f882001-02-23 17:55:21 +00004174 xmlFree(obj);
4175}
4176
4177/**
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004178 * xmlXPathNodeSetClear:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004179 * @set: the node set to clear
Daniel Veillard45490ae2008-07-29 09:13:19 +00004180 *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004181 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4182 * are feed), but does *not* free the list itself. Sets the length of the
4183 * list to 0.
4184 */
4185static void
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004186xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4187{
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004188 if ((set == NULL) || (set->nodeNr <= 0))
4189 return;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004190 else if (hasNsNodes) {
4191 int i;
4192 xmlNodePtr node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004193
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004194 for (i = 0; i < set->nodeNr; i++) {
4195 node = set->nodeTab[i];
4196 if ((node != NULL) &&
4197 (node->type == XML_NAMESPACE_DECL))
4198 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004199 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004200 }
4201 set->nodeNr = 0;
4202}
4203
4204/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004205 * xmlXPathNodeSetClearFromPos:
4206 * @set: the node set to be cleared
4207 * @pos: the start position to clear from
Daniel Veillard45490ae2008-07-29 09:13:19 +00004208 *
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004209 * Clears the list from temporary XPath objects (e.g. namespace nodes
4210 * are feed) starting with the entry at @pos, but does *not* free the list
4211 * itself. Sets the length of the list to @pos.
4212 */
4213static void
4214xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4215{
4216 if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4217 return;
4218 else if ((hasNsNodes)) {
4219 int i;
4220 xmlNodePtr node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004221
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004222 for (i = pos; i < set->nodeNr; i++) {
4223 node = set->nodeTab[i];
4224 if ((node != NULL) &&
4225 (node->type == XML_NAMESPACE_DECL))
4226 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004227 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004228 }
4229 set->nodeNr = pos;
4230}
4231
4232/**
Owen Taylor3473f882001-02-23 17:55:21 +00004233 * xmlXPathFreeValueTree:
4234 * @obj: the xmlNodeSetPtr to free
4235 *
4236 * Free the NodeSet compound and the actual tree, this is different
4237 * from xmlXPathFreeNodeSet()
4238 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004239static void
Owen Taylor3473f882001-02-23 17:55:21 +00004240xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4241 int i;
4242
4243 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00004244
4245 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004246 for (i = 0;i < obj->nodeNr;i++) {
4247 if (obj->nodeTab[i] != NULL) {
4248 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4249 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4250 } else {
4251 xmlFreeNodeList(obj->nodeTab[i]);
4252 }
4253 }
4254 }
Owen Taylor3473f882001-02-23 17:55:21 +00004255 xmlFree(obj->nodeTab);
4256 }
Owen Taylor3473f882001-02-23 17:55:21 +00004257 xmlFree(obj);
4258}
4259
4260#if defined(DEBUG) || defined(DEBUG_STEP)
4261/**
4262 * xmlGenericErrorContextNodeSet:
4263 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00004264 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00004265 *
4266 * Quick display of a NodeSet
4267 */
4268void
4269xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4270 int i;
4271
4272 if (output == NULL) output = xmlGenericErrorContext;
4273 if (obj == NULL) {
4274 fprintf(output, "NodeSet == NULL !\n");
4275 return;
4276 }
4277 if (obj->nodeNr == 0) {
4278 fprintf(output, "NodeSet is empty\n");
4279 return;
4280 }
4281 if (obj->nodeTab == NULL) {
4282 fprintf(output, " nodeTab == NULL !\n");
4283 return;
4284 }
4285 for (i = 0; i < obj->nodeNr; i++) {
4286 if (obj->nodeTab[i] == NULL) {
4287 fprintf(output, " NULL !\n");
4288 return;
4289 }
4290 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4291 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4292 fprintf(output, " /");
4293 else if (obj->nodeTab[i]->name == NULL)
4294 fprintf(output, " noname!");
4295 else fprintf(output, " %s", obj->nodeTab[i]->name);
4296 }
4297 fprintf(output, "\n");
4298}
4299#endif
4300
4301/**
4302 * xmlXPathNewNodeSet:
4303 * @val: the NodePtr value
4304 *
4305 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4306 * it with the single Node @val
4307 *
4308 * Returns the newly created object.
4309 */
4310xmlXPathObjectPtr
4311xmlXPathNewNodeSet(xmlNodePtr val) {
4312 xmlXPathObjectPtr ret;
4313
4314 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4315 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004316 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004317 return(NULL);
4318 }
4319 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4320 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00004321 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004322 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00004323 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004324#ifdef XP_DEBUG_OBJ_USAGE
4325 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4326#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004327 return(ret);
4328}
4329
4330/**
4331 * xmlXPathNewValueTree:
4332 * @val: the NodePtr value
4333 *
4334 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4335 * it with the tree root @val
4336 *
4337 * Returns the newly created object.
4338 */
4339xmlXPathObjectPtr
4340xmlXPathNewValueTree(xmlNodePtr val) {
4341 xmlXPathObjectPtr ret;
4342
4343 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4344 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004345 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004346 return(NULL);
4347 }
4348 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4349 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00004350 ret->boolval = 1;
4351 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00004352 ret->nodesetval = xmlXPathNodeSetCreate(val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004353#ifdef XP_DEBUG_OBJ_USAGE
4354 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4355#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004356 return(ret);
4357}
4358
4359/**
4360 * xmlXPathNewNodeSetList:
4361 * @val: an existing NodeSet
4362 *
4363 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4364 * it with the Nodeset @val
4365 *
4366 * Returns the newly created object.
4367 */
4368xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004369xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4370{
Owen Taylor3473f882001-02-23 17:55:21 +00004371 xmlXPathObjectPtr ret;
4372 int i;
4373
4374 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004375 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00004376 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004377 ret = xmlXPathNewNodeSet(NULL);
4378 else {
4379 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004380 if (ret)
4381 for (i = 1; i < val->nodeNr; ++i)
4382 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004383 }
Owen Taylor3473f882001-02-23 17:55:21 +00004384
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004385 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004386}
4387
4388/**
4389 * xmlXPathWrapNodeSet:
4390 * @val: the NodePtr value
4391 *
4392 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4393 *
4394 * Returns the newly created object.
4395 */
4396xmlXPathObjectPtr
4397xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4398 xmlXPathObjectPtr ret;
4399
4400 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4401 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004402 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004403 return(NULL);
4404 }
4405 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4406 ret->type = XPATH_NODESET;
4407 ret->nodesetval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004408#ifdef XP_DEBUG_OBJ_USAGE
4409 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4410#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004411 return(ret);
4412}
4413
4414/**
4415 * xmlXPathFreeNodeSetList:
4416 * @obj: an existing NodeSetList object
4417 *
4418 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4419 * the list contrary to xmlXPathFreeObject().
4420 */
4421void
4422xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4423 if (obj == NULL) return;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004424#ifdef XP_DEBUG_OBJ_USAGE
4425 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4426#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004427 xmlFree(obj);
4428}
4429
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004430/**
4431 * xmlXPathDifference:
4432 * @nodes1: a node-set
4433 * @nodes2: a node-set
4434 *
4435 * Implements the EXSLT - Sets difference() function:
4436 * node-set set:difference (node-set, node-set)
4437 *
4438 * Returns the difference between the two node sets, or nodes1 if
4439 * nodes2 is empty
4440 */
4441xmlNodeSetPtr
4442xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4443 xmlNodeSetPtr ret;
4444 int i, l1;
4445 xmlNodePtr cur;
4446
4447 if (xmlXPathNodeSetIsEmpty(nodes2))
4448 return(nodes1);
4449
4450 ret = xmlXPathNodeSetCreate(NULL);
4451 if (xmlXPathNodeSetIsEmpty(nodes1))
4452 return(ret);
4453
4454 l1 = xmlXPathNodeSetGetLength(nodes1);
4455
4456 for (i = 0; i < l1; i++) {
4457 cur = xmlXPathNodeSetItem(nodes1, i);
4458 if (!xmlXPathNodeSetContains(nodes2, cur))
4459 xmlXPathNodeSetAddUnique(ret, cur);
4460 }
4461 return(ret);
4462}
4463
4464/**
4465 * xmlXPathIntersection:
4466 * @nodes1: a node-set
4467 * @nodes2: a node-set
4468 *
4469 * Implements the EXSLT - Sets intersection() function:
4470 * node-set set:intersection (node-set, node-set)
4471 *
4472 * Returns a node set comprising the nodes that are within both the
4473 * node sets passed as arguments
4474 */
4475xmlNodeSetPtr
4476xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4477 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4478 int i, l1;
4479 xmlNodePtr cur;
4480
Daniel Veillardf88d8492008-04-01 08:00:31 +00004481 if (ret == NULL)
4482 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004483 if (xmlXPathNodeSetIsEmpty(nodes1))
4484 return(ret);
4485 if (xmlXPathNodeSetIsEmpty(nodes2))
4486 return(ret);
4487
4488 l1 = xmlXPathNodeSetGetLength(nodes1);
4489
4490 for (i = 0; i < l1; i++) {
4491 cur = xmlXPathNodeSetItem(nodes1, i);
4492 if (xmlXPathNodeSetContains(nodes2, cur))
4493 xmlXPathNodeSetAddUnique(ret, cur);
4494 }
4495 return(ret);
4496}
4497
4498/**
4499 * xmlXPathDistinctSorted:
4500 * @nodes: a node-set, sorted by document order
4501 *
4502 * Implements the EXSLT - Sets distinct() function:
4503 * node-set set:distinct (node-set)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004504 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004505 * Returns a subset of the nodes contained in @nodes, or @nodes if
4506 * it is empty
4507 */
4508xmlNodeSetPtr
4509xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4510 xmlNodeSetPtr ret;
4511 xmlHashTablePtr hash;
4512 int i, l;
4513 xmlChar * strval;
4514 xmlNodePtr cur;
4515
4516 if (xmlXPathNodeSetIsEmpty(nodes))
4517 return(nodes);
4518
4519 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004520 if (ret == NULL)
4521 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004522 l = xmlXPathNodeSetGetLength(nodes);
4523 hash = xmlHashCreate (l);
4524 for (i = 0; i < l; i++) {
4525 cur = xmlXPathNodeSetItem(nodes, i);
4526 strval = xmlXPathCastNodeToString(cur);
4527 if (xmlHashLookup(hash, strval) == NULL) {
4528 xmlHashAddEntry(hash, strval, strval);
4529 xmlXPathNodeSetAddUnique(ret, cur);
4530 } else {
4531 xmlFree(strval);
4532 }
4533 }
4534 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4535 return(ret);
4536}
4537
4538/**
4539 * xmlXPathDistinct:
4540 * @nodes: a node-set
4541 *
4542 * Implements the EXSLT - Sets distinct() function:
4543 * node-set set:distinct (node-set)
4544 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4545 * is called with the sorted node-set
4546 *
4547 * Returns a subset of the nodes contained in @nodes, or @nodes if
4548 * it is empty
4549 */
4550xmlNodeSetPtr
4551xmlXPathDistinct (xmlNodeSetPtr nodes) {
4552 if (xmlXPathNodeSetIsEmpty(nodes))
4553 return(nodes);
4554
4555 xmlXPathNodeSetSort(nodes);
4556 return(xmlXPathDistinctSorted(nodes));
4557}
4558
4559/**
4560 * xmlXPathHasSameNodes:
4561 * @nodes1: a node-set
4562 * @nodes2: a node-set
4563 *
4564 * Implements the EXSLT - Sets has-same-nodes function:
4565 * boolean set:has-same-node(node-set, node-set)
4566 *
4567 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4568 * otherwise
4569 */
4570int
4571xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4572 int i, l;
4573 xmlNodePtr cur;
4574
4575 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4576 xmlXPathNodeSetIsEmpty(nodes2))
4577 return(0);
4578
4579 l = xmlXPathNodeSetGetLength(nodes1);
4580 for (i = 0; i < l; i++) {
4581 cur = xmlXPathNodeSetItem(nodes1, i);
4582 if (xmlXPathNodeSetContains(nodes2, cur))
4583 return(1);
4584 }
4585 return(0);
4586}
4587
4588/**
4589 * xmlXPathNodeLeadingSorted:
4590 * @nodes: a node-set, sorted by document order
4591 * @node: a node
4592 *
4593 * Implements the EXSLT - Sets leading() function:
4594 * node-set set:leading (node-set, node-set)
4595 *
4596 * Returns the nodes in @nodes that precede @node in document order,
4597 * @nodes if @node is NULL or an empty node-set if @nodes
4598 * doesn't contain @node
4599 */
4600xmlNodeSetPtr
4601xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4602 int i, l;
4603 xmlNodePtr cur;
4604 xmlNodeSetPtr ret;
4605
4606 if (node == NULL)
4607 return(nodes);
4608
4609 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004610 if (ret == NULL)
4611 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004612 if (xmlXPathNodeSetIsEmpty(nodes) ||
4613 (!xmlXPathNodeSetContains(nodes, node)))
4614 return(ret);
4615
4616 l = xmlXPathNodeSetGetLength(nodes);
4617 for (i = 0; i < l; i++) {
4618 cur = xmlXPathNodeSetItem(nodes, i);
4619 if (cur == node)
4620 break;
4621 xmlXPathNodeSetAddUnique(ret, cur);
4622 }
4623 return(ret);
4624}
4625
4626/**
4627 * xmlXPathNodeLeading:
4628 * @nodes: a node-set
4629 * @node: a node
4630 *
4631 * Implements the EXSLT - Sets leading() function:
4632 * node-set set:leading (node-set, node-set)
4633 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4634 * is called.
4635 *
4636 * Returns the nodes in @nodes that precede @node in document order,
4637 * @nodes if @node is NULL or an empty node-set if @nodes
4638 * doesn't contain @node
4639 */
4640xmlNodeSetPtr
4641xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4642 xmlXPathNodeSetSort(nodes);
4643 return(xmlXPathNodeLeadingSorted(nodes, node));
4644}
4645
4646/**
4647 * xmlXPathLeadingSorted:
4648 * @nodes1: a node-set, sorted by document order
4649 * @nodes2: a node-set, sorted by document order
4650 *
4651 * Implements the EXSLT - Sets leading() function:
4652 * node-set set:leading (node-set, node-set)
4653 *
4654 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4655 * in document order, @nodes1 if @nodes2 is NULL or empty or
4656 * an empty node-set if @nodes1 doesn't contain @nodes2
4657 */
4658xmlNodeSetPtr
4659xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4660 if (xmlXPathNodeSetIsEmpty(nodes2))
4661 return(nodes1);
4662 return(xmlXPathNodeLeadingSorted(nodes1,
4663 xmlXPathNodeSetItem(nodes2, 1)));
4664}
4665
4666/**
4667 * xmlXPathLeading:
4668 * @nodes1: a node-set
4669 * @nodes2: a node-set
4670 *
4671 * Implements the EXSLT - Sets leading() function:
4672 * node-set set:leading (node-set, node-set)
4673 * @nodes1 and @nodes2 are sorted by document order, then
4674 * #exslSetsLeadingSorted is called.
4675 *
4676 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4677 * in document order, @nodes1 if @nodes2 is NULL or empty or
4678 * an empty node-set if @nodes1 doesn't contain @nodes2
4679 */
4680xmlNodeSetPtr
4681xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4682 if (xmlXPathNodeSetIsEmpty(nodes2))
4683 return(nodes1);
4684 if (xmlXPathNodeSetIsEmpty(nodes1))
4685 return(xmlXPathNodeSetCreate(NULL));
4686 xmlXPathNodeSetSort(nodes1);
4687 xmlXPathNodeSetSort(nodes2);
4688 return(xmlXPathNodeLeadingSorted(nodes1,
4689 xmlXPathNodeSetItem(nodes2, 1)));
4690}
4691
4692/**
4693 * xmlXPathNodeTrailingSorted:
4694 * @nodes: a node-set, sorted by document order
4695 * @node: a node
4696 *
4697 * Implements the EXSLT - Sets trailing() function:
4698 * node-set set:trailing (node-set, node-set)
4699 *
4700 * Returns the nodes in @nodes that follow @node in document order,
4701 * @nodes if @node is NULL or an empty node-set if @nodes
4702 * doesn't contain @node
4703 */
4704xmlNodeSetPtr
4705xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4706 int i, l;
4707 xmlNodePtr cur;
4708 xmlNodeSetPtr ret;
4709
4710 if (node == NULL)
4711 return(nodes);
4712
4713 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004714 if (ret == NULL)
4715 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004716 if (xmlXPathNodeSetIsEmpty(nodes) ||
4717 (!xmlXPathNodeSetContains(nodes, node)))
4718 return(ret);
4719
4720 l = xmlXPathNodeSetGetLength(nodes);
William M. Brack97ac8192007-06-06 17:19:24 +00004721 for (i = l - 1; i >= 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004722 cur = xmlXPathNodeSetItem(nodes, i);
4723 if (cur == node)
4724 break;
4725 xmlXPathNodeSetAddUnique(ret, cur);
4726 }
William M. Brack97ac8192007-06-06 17:19:24 +00004727 xmlXPathNodeSetSort(ret); /* bug 413451 */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004728 return(ret);
4729}
4730
4731/**
4732 * xmlXPathNodeTrailing:
4733 * @nodes: a node-set
4734 * @node: a node
4735 *
4736 * Implements the EXSLT - Sets trailing() function:
4737 * node-set set:trailing (node-set, node-set)
4738 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4739 * is called.
4740 *
4741 * Returns the nodes in @nodes that follow @node in document order,
4742 * @nodes if @node is NULL or an empty node-set if @nodes
4743 * doesn't contain @node
4744 */
4745xmlNodeSetPtr
4746xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4747 xmlXPathNodeSetSort(nodes);
4748 return(xmlXPathNodeTrailingSorted(nodes, node));
4749}
4750
4751/**
4752 * xmlXPathTrailingSorted:
4753 * @nodes1: a node-set, sorted by document order
4754 * @nodes2: a node-set, sorted by document order
4755 *
4756 * Implements the EXSLT - Sets trailing() function:
4757 * node-set set:trailing (node-set, node-set)
4758 *
4759 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4760 * in document order, @nodes1 if @nodes2 is NULL or empty or
4761 * an empty node-set if @nodes1 doesn't contain @nodes2
4762 */
4763xmlNodeSetPtr
4764xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4765 if (xmlXPathNodeSetIsEmpty(nodes2))
4766 return(nodes1);
4767 return(xmlXPathNodeTrailingSorted(nodes1,
4768 xmlXPathNodeSetItem(nodes2, 0)));
4769}
4770
4771/**
4772 * xmlXPathTrailing:
4773 * @nodes1: a node-set
4774 * @nodes2: a node-set
4775 *
4776 * Implements the EXSLT - Sets trailing() function:
4777 * node-set set:trailing (node-set, node-set)
4778 * @nodes1 and @nodes2 are sorted by document order, then
4779 * #xmlXPathTrailingSorted is called.
4780 *
4781 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4782 * in document order, @nodes1 if @nodes2 is NULL or empty or
4783 * an empty node-set if @nodes1 doesn't contain @nodes2
4784 */
4785xmlNodeSetPtr
4786xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4787 if (xmlXPathNodeSetIsEmpty(nodes2))
4788 return(nodes1);
4789 if (xmlXPathNodeSetIsEmpty(nodes1))
4790 return(xmlXPathNodeSetCreate(NULL));
4791 xmlXPathNodeSetSort(nodes1);
4792 xmlXPathNodeSetSort(nodes2);
4793 return(xmlXPathNodeTrailingSorted(nodes1,
4794 xmlXPathNodeSetItem(nodes2, 0)));
4795}
4796
Owen Taylor3473f882001-02-23 17:55:21 +00004797/************************************************************************
4798 * *
4799 * Routines to handle extra functions *
4800 * *
4801 ************************************************************************/
4802
4803/**
4804 * xmlXPathRegisterFunc:
4805 * @ctxt: the XPath context
4806 * @name: the function name
4807 * @f: the function implementation or NULL
4808 *
4809 * Register a new function. If @f is NULL it unregisters the function
4810 *
4811 * Returns 0 in case of success, -1 in case of error
4812 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00004813int
Owen Taylor3473f882001-02-23 17:55:21 +00004814xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4815 xmlXPathFunction f) {
4816 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4817}
4818
4819/**
4820 * xmlXPathRegisterFuncNS:
4821 * @ctxt: the XPath context
4822 * @name: the function name
4823 * @ns_uri: the function namespace URI
4824 * @f: the function implementation or NULL
4825 *
4826 * Register a new function. If @f is NULL it unregisters the function
4827 *
4828 * Returns 0 in case of success, -1 in case of error
4829 */
4830int
4831xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4832 const xmlChar *ns_uri, xmlXPathFunction f) {
4833 if (ctxt == NULL)
4834 return(-1);
4835 if (name == NULL)
4836 return(-1);
4837
4838 if (ctxt->funcHash == NULL)
4839 ctxt->funcHash = xmlHashCreate(0);
4840 if (ctxt->funcHash == NULL)
4841 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004842 if (f == NULL)
4843 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
William M. Brackad0e67c2004-12-01 14:35:10 +00004844 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
Owen Taylor3473f882001-02-23 17:55:21 +00004845}
4846
4847/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00004848 * xmlXPathRegisterFuncLookup:
4849 * @ctxt: the XPath context
4850 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004851 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00004852 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004853 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00004854 */
4855void
4856xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4857 xmlXPathFuncLookupFunc f,
4858 void *funcCtxt) {
4859 if (ctxt == NULL)
4860 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004861 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004862 ctxt->funcLookupData = funcCtxt;
4863}
4864
4865/**
Owen Taylor3473f882001-02-23 17:55:21 +00004866 * xmlXPathFunctionLookup:
4867 * @ctxt: the XPath context
4868 * @name: the function name
4869 *
4870 * Search in the Function array of the context for the given
4871 * function.
4872 *
4873 * Returns the xmlXPathFunction or NULL if not found
4874 */
4875xmlXPathFunction
4876xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00004877 if (ctxt == NULL)
4878 return (NULL);
4879
4880 if (ctxt->funcLookupFunc != NULL) {
4881 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004882 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004883
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004884 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004885 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004886 if (ret != NULL)
4887 return(ret);
4888 }
Owen Taylor3473f882001-02-23 17:55:21 +00004889 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4890}
4891
4892/**
4893 * xmlXPathFunctionLookupNS:
4894 * @ctxt: the XPath context
4895 * @name: the function name
4896 * @ns_uri: the function namespace URI
4897 *
4898 * Search in the Function array of the context for the given
4899 * function.
4900 *
4901 * Returns the xmlXPathFunction or NULL if not found
4902 */
4903xmlXPathFunction
4904xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4905 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00004906 xmlXPathFunction ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004907
Owen Taylor3473f882001-02-23 17:55:21 +00004908 if (ctxt == NULL)
4909 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004910 if (name == NULL)
4911 return(NULL);
4912
Thomas Broyerba4ad322001-07-26 16:55:21 +00004913 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004914 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004915
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004916 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004917 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004918 if (ret != NULL)
4919 return(ret);
4920 }
4921
4922 if (ctxt->funcHash == NULL)
4923 return(NULL);
4924
William M. Brackad0e67c2004-12-01 14:35:10 +00004925 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4926 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004927}
4928
4929/**
4930 * xmlXPathRegisteredFuncsCleanup:
4931 * @ctxt: the XPath context
4932 *
4933 * Cleanup the XPath context data associated to registered functions
4934 */
4935void
4936xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4937 if (ctxt == NULL)
4938 return;
4939
4940 xmlHashFree(ctxt->funcHash, NULL);
4941 ctxt->funcHash = NULL;
4942}
4943
4944/************************************************************************
4945 * *
William M. Brack08171912003-12-29 02:52:11 +00004946 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00004947 * *
4948 ************************************************************************/
4949
4950/**
4951 * xmlXPathRegisterVariable:
4952 * @ctxt: the XPath context
4953 * @name: the variable name
4954 * @value: the variable value or NULL
4955 *
4956 * Register a new variable value. If @value is NULL it unregisters
4957 * the variable
4958 *
4959 * Returns 0 in case of success, -1 in case of error
4960 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00004961int
Owen Taylor3473f882001-02-23 17:55:21 +00004962xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4963 xmlXPathObjectPtr value) {
4964 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4965}
4966
4967/**
4968 * xmlXPathRegisterVariableNS:
4969 * @ctxt: the XPath context
4970 * @name: the variable name
4971 * @ns_uri: the variable namespace URI
4972 * @value: the variable value or NULL
4973 *
4974 * Register a new variable value. If @value is NULL it unregisters
4975 * the variable
4976 *
4977 * Returns 0 in case of success, -1 in case of error
4978 */
4979int
4980xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4981 const xmlChar *ns_uri,
4982 xmlXPathObjectPtr value) {
4983 if (ctxt == NULL)
4984 return(-1);
4985 if (name == NULL)
4986 return(-1);
4987
4988 if (ctxt->varHash == NULL)
4989 ctxt->varHash = xmlHashCreate(0);
4990 if (ctxt->varHash == NULL)
4991 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004992 if (value == NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004993 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
Daniel Veillard94394cd2003-10-29 17:07:51 +00004994 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00004995 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4996 (void *) value,
4997 (xmlHashDeallocator)xmlXPathFreeObject));
4998}
4999
5000/**
5001 * xmlXPathRegisterVariableLookup:
5002 * @ctxt: the XPath context
5003 * @f: the lookup function
5004 * @data: the lookup data
5005 *
5006 * register an external mechanism to do variable lookup
5007 */
5008void
5009xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5010 xmlXPathVariableLookupFunc f, void *data) {
5011 if (ctxt == NULL)
5012 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00005013 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00005014 ctxt->varLookupData = data;
5015}
5016
5017/**
5018 * xmlXPathVariableLookup:
5019 * @ctxt: the XPath context
5020 * @name: the variable name
5021 *
5022 * Search in the Variable array of the context for the given
5023 * variable value.
5024 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00005025 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00005026 */
5027xmlXPathObjectPtr
5028xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5029 if (ctxt == NULL)
5030 return(NULL);
5031
5032 if (ctxt->varLookupFunc != NULL) {
5033 xmlXPathObjectPtr ret;
5034
5035 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5036 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00005037 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00005038 }
5039 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5040}
5041
5042/**
5043 * xmlXPathVariableLookupNS:
5044 * @ctxt: the XPath context
5045 * @name: the variable name
5046 * @ns_uri: the variable namespace URI
5047 *
5048 * Search in the Variable array of the context for the given
Daniel Veillard45490ae2008-07-29 09:13:19 +00005049 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00005050 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00005051 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00005052 */
5053xmlXPathObjectPtr
5054xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5055 const xmlChar *ns_uri) {
5056 if (ctxt == NULL)
5057 return(NULL);
5058
5059 if (ctxt->varLookupFunc != NULL) {
5060 xmlXPathObjectPtr ret;
5061
5062 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5063 (ctxt->varLookupData, name, ns_uri);
5064 if (ret != NULL) return(ret);
5065 }
5066
5067 if (ctxt->varHash == NULL)
5068 return(NULL);
5069 if (name == NULL)
5070 return(NULL);
5071
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005072 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
Daniel Veillard8c357d52001-07-03 23:43:33 +00005073 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00005074}
5075
5076/**
5077 * xmlXPathRegisteredVariablesCleanup:
5078 * @ctxt: the XPath context
5079 *
5080 * Cleanup the XPath context data associated to registered variables
5081 */
5082void
5083xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5084 if (ctxt == NULL)
5085 return;
5086
Daniel Veillard76d66f42001-05-16 21:05:17 +00005087 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00005088 ctxt->varHash = NULL;
5089}
5090
5091/**
5092 * xmlXPathRegisterNs:
5093 * @ctxt: the XPath context
Daniel Veillarddb3ce962009-03-25 09:43:49 +00005094 * @prefix: the namespace prefix cannot be NULL or empty string
Owen Taylor3473f882001-02-23 17:55:21 +00005095 * @ns_uri: the namespace name
5096 *
5097 * Register a new namespace. If @ns_uri is NULL it unregisters
5098 * the namespace
5099 *
5100 * Returns 0 in case of success, -1 in case of error
5101 */
5102int
5103xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5104 const xmlChar *ns_uri) {
5105 if (ctxt == NULL)
5106 return(-1);
5107 if (prefix == NULL)
5108 return(-1);
Daniel Veillarddb3ce962009-03-25 09:43:49 +00005109 if (prefix[0] == 0)
5110 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00005111
5112 if (ctxt->nsHash == NULL)
5113 ctxt->nsHash = xmlHashCreate(10);
5114 if (ctxt->nsHash == NULL)
5115 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00005116 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00005117 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00005118 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00005119 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00005120 (xmlHashDeallocator)xmlFree));
5121}
5122
5123/**
5124 * xmlXPathNsLookup:
5125 * @ctxt: the XPath context
5126 * @prefix: the namespace prefix value
5127 *
5128 * Search in the namespace declaration array of the context for the given
5129 * namespace name associated to the given prefix
5130 *
5131 * Returns the value or NULL if not found
5132 */
5133const xmlChar *
5134xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5135 if (ctxt == NULL)
5136 return(NULL);
5137 if (prefix == NULL)
5138 return(NULL);
5139
5140#ifdef XML_XML_NAMESPACE
5141 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5142 return(XML_XML_NAMESPACE);
5143#endif
5144
Daniel Veillardc8f620b2001-04-30 20:31:33 +00005145 if (ctxt->namespaces != NULL) {
5146 int i;
5147
5148 for (i = 0;i < ctxt->nsNr;i++) {
5149 if ((ctxt->namespaces[i] != NULL) &&
5150 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5151 return(ctxt->namespaces[i]->href);
5152 }
5153 }
Owen Taylor3473f882001-02-23 17:55:21 +00005154
5155 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5156}
5157
5158/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005159 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00005160 * @ctxt: the XPath context
5161 *
5162 * Cleanup the XPath context data associated to registered variables
5163 */
5164void
5165xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5166 if (ctxt == NULL)
5167 return;
5168
Daniel Veillard42766c02002-08-22 20:52:17 +00005169 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00005170 ctxt->nsHash = NULL;
5171}
5172
5173/************************************************************************
5174 * *
5175 * Routines to handle Values *
5176 * *
5177 ************************************************************************/
5178
William M. Brack08171912003-12-29 02:52:11 +00005179/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005180
5181/**
5182 * xmlXPathNewFloat:
5183 * @val: the double value
5184 *
5185 * Create a new xmlXPathObjectPtr of type double and of value @val
5186 *
5187 * Returns the newly created object.
5188 */
5189xmlXPathObjectPtr
5190xmlXPathNewFloat(double val) {
5191 xmlXPathObjectPtr ret;
5192
5193 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5194 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005195 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005196 return(NULL);
5197 }
5198 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5199 ret->type = XPATH_NUMBER;
5200 ret->floatval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005201#ifdef XP_DEBUG_OBJ_USAGE
5202 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5203#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005204 return(ret);
5205}
5206
5207/**
5208 * xmlXPathNewBoolean:
5209 * @val: the boolean value
5210 *
5211 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5212 *
5213 * Returns the newly created object.
5214 */
5215xmlXPathObjectPtr
5216xmlXPathNewBoolean(int 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 boolean 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_BOOLEAN;
5226 ret->boolval = (val != 0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005227#ifdef XP_DEBUG_OBJ_USAGE
5228 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5229#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005230 return(ret);
5231}
5232
5233/**
5234 * xmlXPathNewString:
5235 * @val: the xmlChar * value
5236 *
5237 * Create a new xmlXPathObjectPtr of type string and of value @val
5238 *
5239 * Returns the newly created object.
5240 */
5241xmlXPathObjectPtr
5242xmlXPathNewString(const xmlChar *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 string 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_STRING;
5252 if (val != NULL)
5253 ret->stringval = xmlStrdup(val);
5254 else
5255 ret->stringval = xmlStrdup((const xmlChar *)"");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005256#ifdef XP_DEBUG_OBJ_USAGE
5257 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5258#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005259 return(ret);
5260}
5261
5262/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005263 * xmlXPathWrapString:
5264 * @val: the xmlChar * value
5265 *
5266 * Wraps the @val string into an XPath object.
5267 *
5268 * Returns the newly created object.
5269 */
5270xmlXPathObjectPtr
5271xmlXPathWrapString (xmlChar *val) {
5272 xmlXPathObjectPtr ret;
5273
5274 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5275 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005276 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005277 return(NULL);
5278 }
5279 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5280 ret->type = XPATH_STRING;
5281 ret->stringval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005282#ifdef XP_DEBUG_OBJ_USAGE
5283 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5284#endif
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005285 return(ret);
5286}
5287
5288/**
Owen Taylor3473f882001-02-23 17:55:21 +00005289 * xmlXPathNewCString:
5290 * @val: the char * value
5291 *
5292 * Create a new xmlXPathObjectPtr of type string and of value @val
5293 *
5294 * Returns the newly created object.
5295 */
5296xmlXPathObjectPtr
5297xmlXPathNewCString(const char *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");
Owen Taylor3473f882001-02-23 17:55:21 +00005303 return(NULL);
5304 }
5305 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5306 ret->type = XPATH_STRING;
5307 ret->stringval = xmlStrdup(BAD_CAST val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005308#ifdef XP_DEBUG_OBJ_USAGE
5309 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5310#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005311 return(ret);
5312}
5313
5314/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005315 * xmlXPathWrapCString:
5316 * @val: the char * value
5317 *
5318 * Wraps a string into an XPath object.
5319 *
5320 * Returns the newly created object.
5321 */
5322xmlXPathObjectPtr
5323xmlXPathWrapCString (char * val) {
5324 return(xmlXPathWrapString((xmlChar *)(val)));
5325}
5326
5327/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005328 * xmlXPathWrapExternal:
5329 * @val: the user data
5330 *
5331 * Wraps the @val data into an XPath object.
5332 *
5333 * Returns the newly created object.
5334 */
5335xmlXPathObjectPtr
5336xmlXPathWrapExternal (void *val) {
5337 xmlXPathObjectPtr ret;
5338
5339 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5340 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005341 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005342 return(NULL);
5343 }
5344 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5345 ret->type = XPATH_USERS;
5346 ret->user = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005347#ifdef XP_DEBUG_OBJ_USAGE
5348 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5349#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005350 return(ret);
5351}
5352
5353/**
Owen Taylor3473f882001-02-23 17:55:21 +00005354 * xmlXPathObjectCopy:
5355 * @val: the original object
5356 *
5357 * allocate a new copy of a given object
5358 *
5359 * Returns the newly created object.
5360 */
5361xmlXPathObjectPtr
5362xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5363 xmlXPathObjectPtr ret;
5364
5365 if (val == NULL)
5366 return(NULL);
5367
5368 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5369 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005370 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005371 return(NULL);
5372 }
5373 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005374#ifdef XP_DEBUG_OBJ_USAGE
5375 xmlXPathDebugObjUsageRequested(NULL, val->type);
5376#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005377 switch (val->type) {
5378 case XPATH_BOOLEAN:
5379 case XPATH_NUMBER:
5380 case XPATH_POINT:
5381 case XPATH_RANGE:
5382 break;
5383 case XPATH_STRING:
5384 ret->stringval = xmlStrdup(val->stringval);
5385 break;
5386 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00005387#if 0
5388/*
5389 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5390 this previous handling is no longer correct, and can cause some serious
5391 problems (ref. bug 145547)
5392*/
Owen Taylor3473f882001-02-23 17:55:21 +00005393 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005394 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005395 xmlNodePtr cur, tmp;
5396 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005397
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005398 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005399 top = xmlNewDoc(NULL);
5400 top->name = (char *)
5401 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005402 ret->user = top;
5403 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005404 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005405 cur = val->nodesetval->nodeTab[0]->children;
5406 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005407 tmp = xmlDocCopyNode(cur, top, 1);
5408 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005409 cur = cur->next;
5410 }
5411 }
William M. Bracke9449c52004-07-11 14:41:20 +00005412
Daniel Veillard9adc0462003-03-24 18:39:54 +00005413 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005414 } else
Owen Taylor3473f882001-02-23 17:55:21 +00005415 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005416 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00005417 break;
William M. Bracke9449c52004-07-11 14:41:20 +00005418#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005419 case XPATH_NODESET:
5420 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005421 /* Do not deallocate the copied tree value */
5422 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005423 break;
5424 case XPATH_LOCATIONSET:
5425#ifdef LIBXML_XPTR_ENABLED
5426 {
5427 xmlLocationSetPtr loc = val->user;
5428 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5429 break;
5430 }
5431#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00005432 case XPATH_USERS:
5433 ret->user = val->user;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005434 break;
Thomas Broyer47334c02001-10-07 16:41:52 +00005435 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00005436 xmlGenericError(xmlGenericErrorContext,
5437 "xmlXPathObjectCopy: unsupported type %d\n",
5438 val->type);
5439 break;
5440 }
5441 return(ret);
5442}
5443
5444/**
5445 * xmlXPathFreeObject:
5446 * @obj: the object to free
5447 *
5448 * Free up an xmlXPathObjectPtr object.
5449 */
5450void
5451xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5452 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005453 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00005454 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00005455#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005456 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005457 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00005458 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00005459 } else
5460#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005461 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
William M. Bracke9449c52004-07-11 14:41:20 +00005462 if (obj->nodesetval != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00005463 xmlXPathFreeValueTree(obj->nodesetval);
Daniel Veillard77851712001-02-27 21:54:07 +00005464 } else {
5465 if (obj->nodesetval != NULL)
5466 xmlXPathFreeNodeSet(obj->nodesetval);
5467 }
Owen Taylor3473f882001-02-23 17:55:21 +00005468#ifdef LIBXML_XPTR_ENABLED
5469 } else if (obj->type == XPATH_LOCATIONSET) {
5470 if (obj->user != NULL)
5471 xmlXPtrFreeLocationSet(obj->user);
5472#endif
5473 } else if (obj->type == XPATH_STRING) {
5474 if (obj->stringval != NULL)
5475 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005476 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005477#ifdef XP_DEBUG_OBJ_USAGE
5478 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5479#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00005480 xmlFree(obj);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005481}
Owen Taylor3473f882001-02-23 17:55:21 +00005482
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005483/**
5484 * xmlXPathReleaseObject:
5485 * @obj: the xmlXPathObjectPtr to free or to cache
5486 *
5487 * Depending on the state of the cache this frees the given
5488 * XPath object or stores it in the cache.
5489 */
5490static void
5491xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5492{
5493#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5494 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5495 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5496
5497#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5498
5499 if (obj == NULL)
5500 return;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005501 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005502 xmlXPathFreeObject(obj);
Daniel Veillard45490ae2008-07-29 09:13:19 +00005503 } else {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005504 xmlXPathContextCachePtr cache =
5505 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005506
5507 switch (obj->type) {
5508 case XPATH_NODESET:
5509 case XPATH_XSLT_TREE:
5510 if (obj->nodesetval != NULL) {
5511 if (obj->boolval) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00005512 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005513 * It looks like the @boolval is used for
5514 * evaluation if this an XSLT Result Tree Fragment.
5515 * TODO: Check if this assumption is correct.
5516 */
5517 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5518 xmlXPathFreeValueTree(obj->nodesetval);
5519 obj->nodesetval = NULL;
5520 } else if ((obj->nodesetval->nodeMax <= 40) &&
5521 (XP_CACHE_WANTS(cache->nodesetObjs,
5522 cache->maxNodeset)))
5523 {
5524 XP_CACHE_ADD(cache->nodesetObjs, obj);
5525 goto obj_cached;
5526 } else {
5527 xmlXPathFreeNodeSet(obj->nodesetval);
5528 obj->nodesetval = NULL;
5529 }
5530 }
5531 break;
5532 case XPATH_STRING:
5533 if (obj->stringval != NULL)
5534 xmlFree(obj->stringval);
5535
5536 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5537 XP_CACHE_ADD(cache->stringObjs, obj);
5538 goto obj_cached;
5539 }
5540 break;
5541 case XPATH_BOOLEAN:
5542 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5543 XP_CACHE_ADD(cache->booleanObjs, obj);
5544 goto obj_cached;
5545 }
5546 break;
5547 case XPATH_NUMBER:
5548 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5549 XP_CACHE_ADD(cache->numberObjs, obj);
5550 goto obj_cached;
5551 }
5552 break;
5553#ifdef LIBXML_XPTR_ENABLED
5554 case XPATH_LOCATIONSET:
5555 if (obj->user != NULL) {
5556 xmlXPtrFreeLocationSet(obj->user);
5557 }
5558 goto free_obj;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005559#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005560 default:
5561 goto free_obj;
5562 }
5563
5564 /*
5565 * Fallback to adding to the misc-objects slot.
5566 */
5567 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5568 XP_CACHE_ADD(cache->miscObjs, obj);
5569 } else
5570 goto free_obj;
5571
5572obj_cached:
5573
5574#ifdef XP_DEBUG_OBJ_USAGE
5575 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5576#endif
5577
5578 if (obj->nodesetval != NULL) {
5579 xmlNodeSetPtr tmpset = obj->nodesetval;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005580
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005581 /*
5582 * TODO: Due to those nasty ns-nodes, we need to traverse
5583 * the list and free the ns-nodes.
5584 * URGENT TODO: Check if it's actually slowing things down.
5585 * Maybe we shouldn't try to preserve the list.
5586 */
5587 if (tmpset->nodeNr > 1) {
5588 int i;
5589 xmlNodePtr node;
5590
5591 for (i = 0; i < tmpset->nodeNr; i++) {
5592 node = tmpset->nodeTab[i];
5593 if ((node != NULL) &&
5594 (node->type == XML_NAMESPACE_DECL))
5595 {
5596 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5597 }
5598 }
5599 } else if (tmpset->nodeNr == 1) {
5600 if ((tmpset->nodeTab[0] != NULL) &&
5601 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5602 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
Daniel Veillard45490ae2008-07-29 09:13:19 +00005603 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005604 tmpset->nodeNr = 0;
5605 memset(obj, 0, sizeof(xmlXPathObject));
5606 obj->nodesetval = tmpset;
5607 } else
5608 memset(obj, 0, sizeof(xmlXPathObject));
5609
5610 return;
5611
5612free_obj:
5613 /*
5614 * Cache is full; free the object.
Daniel Veillard45490ae2008-07-29 09:13:19 +00005615 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005616 if (obj->nodesetval != NULL)
5617 xmlXPathFreeNodeSet(obj->nodesetval);
5618#ifdef XP_DEBUG_OBJ_USAGE
5619 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5620#endif
5621 xmlFree(obj);
5622 }
5623 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005624}
5625
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005626
5627/************************************************************************
5628 * *
5629 * Type Casting Routines *
5630 * *
5631 ************************************************************************/
5632
5633/**
5634 * xmlXPathCastBooleanToString:
5635 * @val: a boolean
5636 *
5637 * Converts a boolean to its string value.
5638 *
5639 * Returns a newly allocated string.
5640 */
5641xmlChar *
5642xmlXPathCastBooleanToString (int val) {
5643 xmlChar *ret;
5644 if (val)
5645 ret = xmlStrdup((const xmlChar *) "true");
5646 else
5647 ret = xmlStrdup((const xmlChar *) "false");
5648 return(ret);
5649}
5650
5651/**
5652 * xmlXPathCastNumberToString:
5653 * @val: a number
5654 *
5655 * Converts a number to its string value.
5656 *
5657 * Returns a newly allocated string.
5658 */
5659xmlChar *
5660xmlXPathCastNumberToString (double val) {
5661 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00005662 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005663 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005664 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005665 break;
5666 case -1:
5667 ret = xmlStrdup((const xmlChar *) "-Infinity");
5668 break;
5669 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00005670 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005671 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005672 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5673 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005674 } else {
5675 /* could be improved */
5676 char buf[100];
Daniel Veillard11ce4002006-03-10 00:36:23 +00005677 xmlXPathFormatNumber(val, buf, 99);
5678 buf[99] = 0;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005679 ret = xmlStrdup((const xmlChar *) buf);
5680 }
5681 }
5682 return(ret);
5683}
5684
5685/**
5686 * xmlXPathCastNodeToString:
5687 * @node: a node
5688 *
5689 * Converts a node to its string value.
5690 *
5691 * Returns a newly allocated string.
5692 */
5693xmlChar *
5694xmlXPathCastNodeToString (xmlNodePtr node) {
William M. Brackd611c882007-05-31 05:07:17 +00005695xmlChar *ret;
5696 if ((ret = xmlNodeGetContent(node)) == NULL)
5697 ret = xmlStrdup((const xmlChar *) "");
5698 return(ret);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005699}
5700
5701/**
5702 * xmlXPathCastNodeSetToString:
5703 * @ns: a node-set
5704 *
5705 * Converts a node-set to its string value.
5706 *
5707 * Returns a newly allocated string.
5708 */
5709xmlChar *
5710xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5711 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5712 return(xmlStrdup((const xmlChar *) ""));
5713
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00005714 if (ns->nodeNr > 1)
5715 xmlXPathNodeSetSort(ns);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005716 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5717}
5718
5719/**
5720 * xmlXPathCastToString:
5721 * @val: an XPath object
5722 *
5723 * Converts an existing object to its string() equivalent
5724 *
Kasimier T. Buchcik50128ad2006-08-15 13:04:07 +00005725 * Returns the allocated string value of the object, NULL in case of error.
Daniel Veillard45490ae2008-07-29 09:13:19 +00005726 * It's up to the caller to free the string memory with xmlFree().
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005727 */
5728xmlChar *
5729xmlXPathCastToString(xmlXPathObjectPtr val) {
5730 xmlChar *ret = NULL;
5731
5732 if (val == NULL)
5733 return(xmlStrdup((const xmlChar *) ""));
5734 switch (val->type) {
5735 case XPATH_UNDEFINED:
5736#ifdef DEBUG_EXPR
5737 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5738#endif
5739 ret = xmlStrdup((const xmlChar *) "");
5740 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005741 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005742 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005743 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5744 break;
5745 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00005746 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005747 case XPATH_BOOLEAN:
5748 ret = xmlXPathCastBooleanToString(val->boolval);
5749 break;
5750 case XPATH_NUMBER: {
5751 ret = xmlXPathCastNumberToString(val->floatval);
5752 break;
5753 }
5754 case XPATH_USERS:
5755 case XPATH_POINT:
5756 case XPATH_RANGE:
5757 case XPATH_LOCATIONSET:
5758 TODO
5759 ret = xmlStrdup((const xmlChar *) "");
5760 break;
5761 }
5762 return(ret);
5763}
5764
5765/**
5766 * xmlXPathConvertString:
5767 * @val: an XPath object
5768 *
5769 * Converts an existing object to its string() equivalent
5770 *
5771 * Returns the new object, the old one is freed (or the operation
5772 * is done directly on @val)
5773 */
5774xmlXPathObjectPtr
5775xmlXPathConvertString(xmlXPathObjectPtr val) {
5776 xmlChar *res = NULL;
5777
5778 if (val == NULL)
5779 return(xmlXPathNewCString(""));
5780
5781 switch (val->type) {
5782 case XPATH_UNDEFINED:
5783#ifdef DEBUG_EXPR
5784 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5785#endif
5786 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005787 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005788 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005789 res = xmlXPathCastNodeSetToString(val->nodesetval);
5790 break;
5791 case XPATH_STRING:
5792 return(val);
5793 case XPATH_BOOLEAN:
5794 res = xmlXPathCastBooleanToString(val->boolval);
5795 break;
5796 case XPATH_NUMBER:
5797 res = xmlXPathCastNumberToString(val->floatval);
5798 break;
5799 case XPATH_USERS:
5800 case XPATH_POINT:
5801 case XPATH_RANGE:
5802 case XPATH_LOCATIONSET:
5803 TODO;
5804 break;
5805 }
5806 xmlXPathFreeObject(val);
5807 if (res == NULL)
5808 return(xmlXPathNewCString(""));
5809 return(xmlXPathWrapString(res));
5810}
5811
5812/**
5813 * xmlXPathCastBooleanToNumber:
5814 * @val: a boolean
5815 *
5816 * Converts a boolean to its number value
5817 *
5818 * Returns the number value
5819 */
5820double
5821xmlXPathCastBooleanToNumber(int val) {
5822 if (val)
5823 return(1.0);
5824 return(0.0);
5825}
5826
5827/**
5828 * xmlXPathCastStringToNumber:
5829 * @val: a string
5830 *
5831 * Converts a string to its number value
5832 *
5833 * Returns the number value
5834 */
5835double
5836xmlXPathCastStringToNumber(const xmlChar * val) {
5837 return(xmlXPathStringEvalNumber(val));
5838}
5839
5840/**
5841 * xmlXPathCastNodeToNumber:
5842 * @node: a node
5843 *
5844 * Converts a node to its number value
5845 *
5846 * Returns the number value
5847 */
5848double
5849xmlXPathCastNodeToNumber (xmlNodePtr node) {
5850 xmlChar *strval;
5851 double ret;
5852
5853 if (node == NULL)
5854 return(xmlXPathNAN);
5855 strval = xmlXPathCastNodeToString(node);
5856 if (strval == NULL)
5857 return(xmlXPathNAN);
5858 ret = xmlXPathCastStringToNumber(strval);
5859 xmlFree(strval);
5860
5861 return(ret);
5862}
5863
5864/**
5865 * xmlXPathCastNodeSetToNumber:
5866 * @ns: a node-set
5867 *
5868 * Converts a node-set to its number value
5869 *
5870 * Returns the number value
5871 */
5872double
5873xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5874 xmlChar *str;
5875 double ret;
5876
5877 if (ns == NULL)
5878 return(xmlXPathNAN);
5879 str = xmlXPathCastNodeSetToString(ns);
5880 ret = xmlXPathCastStringToNumber(str);
5881 xmlFree(str);
5882 return(ret);
5883}
5884
5885/**
5886 * xmlXPathCastToNumber:
5887 * @val: an XPath object
5888 *
5889 * Converts an XPath object to its number value
5890 *
5891 * Returns the number value
5892 */
5893double
5894xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5895 double ret = 0.0;
5896
5897 if (val == NULL)
5898 return(xmlXPathNAN);
5899 switch (val->type) {
5900 case XPATH_UNDEFINED:
5901#ifdef DEGUB_EXPR
5902 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5903#endif
5904 ret = xmlXPathNAN;
5905 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005906 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005907 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005908 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5909 break;
5910 case XPATH_STRING:
5911 ret = xmlXPathCastStringToNumber(val->stringval);
5912 break;
5913 case XPATH_NUMBER:
5914 ret = val->floatval;
5915 break;
5916 case XPATH_BOOLEAN:
5917 ret = xmlXPathCastBooleanToNumber(val->boolval);
5918 break;
5919 case XPATH_USERS:
5920 case XPATH_POINT:
5921 case XPATH_RANGE:
5922 case XPATH_LOCATIONSET:
5923 TODO;
5924 ret = xmlXPathNAN;
5925 break;
5926 }
5927 return(ret);
5928}
5929
5930/**
5931 * xmlXPathConvertNumber:
5932 * @val: an XPath object
5933 *
5934 * Converts an existing object to its number() equivalent
5935 *
5936 * Returns the new object, the old one is freed (or the operation
5937 * is done directly on @val)
5938 */
5939xmlXPathObjectPtr
5940xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5941 xmlXPathObjectPtr ret;
5942
5943 if (val == NULL)
5944 return(xmlXPathNewFloat(0.0));
5945 if (val->type == XPATH_NUMBER)
5946 return(val);
5947 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5948 xmlXPathFreeObject(val);
5949 return(ret);
5950}
5951
5952/**
5953 * xmlXPathCastNumberToBoolean:
5954 * @val: a number
5955 *
5956 * Converts a number to its boolean value
5957 *
5958 * Returns the boolean value
5959 */
5960int
5961xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00005962 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005963 return(0);
5964 return(1);
5965}
5966
5967/**
5968 * xmlXPathCastStringToBoolean:
5969 * @val: a string
5970 *
5971 * Converts a string to its boolean value
5972 *
5973 * Returns the boolean value
5974 */
5975int
5976xmlXPathCastStringToBoolean (const xmlChar *val) {
5977 if ((val == NULL) || (xmlStrlen(val) == 0))
5978 return(0);
5979 return(1);
5980}
5981
5982/**
5983 * xmlXPathCastNodeSetToBoolean:
5984 * @ns: a node-set
5985 *
5986 * Converts a node-set to its boolean value
5987 *
5988 * Returns the boolean value
5989 */
5990int
5991xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5992 if ((ns == NULL) || (ns->nodeNr == 0))
5993 return(0);
5994 return(1);
5995}
5996
5997/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005998 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005999 * @val: an XPath object
6000 *
6001 * Converts an XPath object to its boolean value
6002 *
6003 * Returns the boolean value
6004 */
6005int
6006xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6007 int ret = 0;
6008
6009 if (val == NULL)
6010 return(0);
6011 switch (val->type) {
6012 case XPATH_UNDEFINED:
6013#ifdef DEBUG_EXPR
6014 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6015#endif
6016 ret = 0;
6017 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006018 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00006019 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006020 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6021 break;
6022 case XPATH_STRING:
6023 ret = xmlXPathCastStringToBoolean(val->stringval);
6024 break;
6025 case XPATH_NUMBER:
6026 ret = xmlXPathCastNumberToBoolean(val->floatval);
6027 break;
6028 case XPATH_BOOLEAN:
6029 ret = val->boolval;
6030 break;
6031 case XPATH_USERS:
6032 case XPATH_POINT:
6033 case XPATH_RANGE:
6034 case XPATH_LOCATIONSET:
6035 TODO;
6036 ret = 0;
6037 break;
6038 }
6039 return(ret);
6040}
6041
6042
6043/**
6044 * xmlXPathConvertBoolean:
6045 * @val: an XPath object
6046 *
6047 * Converts an existing object to its boolean() equivalent
6048 *
6049 * Returns the new object, the old one is freed (or the operation
6050 * is done directly on @val)
6051 */
6052xmlXPathObjectPtr
6053xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6054 xmlXPathObjectPtr ret;
6055
6056 if (val == NULL)
6057 return(xmlXPathNewBoolean(0));
6058 if (val->type == XPATH_BOOLEAN)
6059 return(val);
6060 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6061 xmlXPathFreeObject(val);
6062 return(ret);
6063}
6064
Owen Taylor3473f882001-02-23 17:55:21 +00006065/************************************************************************
6066 * *
6067 * Routines to handle XPath contexts *
6068 * *
6069 ************************************************************************/
6070
6071/**
6072 * xmlXPathNewContext:
6073 * @doc: the XML document
6074 *
6075 * Create a new xmlXPathContext
6076 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00006077 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00006078 */
6079xmlXPathContextPtr
6080xmlXPathNewContext(xmlDocPtr doc) {
6081 xmlXPathContextPtr ret;
6082
6083 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6084 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006085 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006086 return(NULL);
6087 }
6088 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6089 ret->doc = doc;
6090 ret->node = NULL;
6091
6092 ret->varHash = NULL;
6093
6094 ret->nb_types = 0;
6095 ret->max_types = 0;
6096 ret->types = NULL;
6097
6098 ret->funcHash = xmlHashCreate(0);
6099
6100 ret->nb_axis = 0;
6101 ret->max_axis = 0;
6102 ret->axis = NULL;
6103
6104 ret->nsHash = NULL;
6105 ret->user = NULL;
6106
6107 ret->contextSize = -1;
6108 ret->proximityPosition = -1;
6109
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006110#ifdef XP_DEFAULT_CACHE_ON
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006111 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006112 xmlXPathFreeContext(ret);
6113 return(NULL);
6114 }
6115#endif
6116
Daniel Veillard45490ae2008-07-29 09:13:19 +00006117 xmlXPathRegisterAllFunctions(ret);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006118
Owen Taylor3473f882001-02-23 17:55:21 +00006119 return(ret);
6120}
6121
6122/**
6123 * xmlXPathFreeContext:
6124 * @ctxt: the context to free
6125 *
6126 * Free up an xmlXPathContext
6127 */
6128void
6129xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006130 if (ctxt == NULL) return;
6131
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006132 if (ctxt->cache != NULL)
6133 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
Owen Taylor3473f882001-02-23 17:55:21 +00006134 xmlXPathRegisteredNsCleanup(ctxt);
6135 xmlXPathRegisteredFuncsCleanup(ctxt);
6136 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006137 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00006138 xmlFree(ctxt);
6139}
6140
6141/************************************************************************
6142 * *
6143 * Routines to handle XPath parser contexts *
6144 * *
6145 ************************************************************************/
6146
6147#define CHECK_CTXT(ctxt) \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006148 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00006149 __xmlRaiseError(NULL, NULL, NULL, \
6150 NULL, NULL, XML_FROM_XPATH, \
6151 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6152 __FILE__, __LINE__, \
6153 NULL, NULL, NULL, 0, 0, \
6154 "NULL context pointer\n"); \
6155 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00006156 } \
6157
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006158#define CHECK_CTXT_NEG(ctxt) \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006159 if (ctxt == NULL) { \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006160 __xmlRaiseError(NULL, NULL, NULL, \
6161 NULL, NULL, XML_FROM_XPATH, \
6162 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6163 __FILE__, __LINE__, \
6164 NULL, NULL, NULL, 0, 0, \
6165 "NULL context pointer\n"); \
6166 return(-1); \
6167 } \
6168
Owen Taylor3473f882001-02-23 17:55:21 +00006169
6170#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00006171 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006172 (ctxt->doc->children == NULL)) { \
Daniel Veillard57b25162004-11-06 14:50:18 +00006173 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00006174 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00006175 }
Owen Taylor3473f882001-02-23 17:55:21 +00006176
6177
6178/**
6179 * xmlXPathNewParserContext:
6180 * @str: the XPath expression
6181 * @ctxt: the XPath context
6182 *
6183 * Create a new xmlXPathParserContext
6184 *
6185 * Returns the xmlXPathParserContext just allocated.
6186 */
6187xmlXPathParserContextPtr
6188xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6189 xmlXPathParserContextPtr ret;
6190
6191 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6192 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006193 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006194 return(NULL);
6195 }
6196 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6197 ret->cur = ret->base = str;
6198 ret->context = ctxt;
6199
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006200 ret->comp = xmlXPathNewCompExpr();
6201 if (ret->comp == NULL) {
6202 xmlFree(ret->valueTab);
6203 xmlFree(ret);
6204 return(NULL);
6205 }
Daniel Veillard4773df22004-01-23 13:15:13 +00006206 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6207 ret->comp->dict = ctxt->dict;
6208 xmlDictReference(ret->comp->dict);
6209 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006210
6211 return(ret);
6212}
6213
6214/**
6215 * xmlXPathCompParserContext:
6216 * @comp: the XPath compiled expression
6217 * @ctxt: the XPath context
6218 *
6219 * Create a new xmlXPathParserContext when processing a compiled expression
6220 *
6221 * Returns the xmlXPathParserContext just allocated.
6222 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006223static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006224xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6225 xmlXPathParserContextPtr ret;
6226
6227 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6228 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006229 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006230 return(NULL);
6231 }
6232 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6233
Owen Taylor3473f882001-02-23 17:55:21 +00006234 /* Allocate the value stack */
Daniel Veillard45490ae2008-07-29 09:13:19 +00006235 ret->valueTab = (xmlXPathObjectPtr *)
Owen Taylor3473f882001-02-23 17:55:21 +00006236 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006237 if (ret->valueTab == NULL) {
6238 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006239 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006240 return(NULL);
6241 }
Owen Taylor3473f882001-02-23 17:55:21 +00006242 ret->valueNr = 0;
6243 ret->valueMax = 10;
6244 ret->value = NULL;
Daniel Veillardf5048b32011-08-18 17:10:13 +08006245 ret->valueFrame = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006246
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006247 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006248 ret->comp = comp;
6249
Owen Taylor3473f882001-02-23 17:55:21 +00006250 return(ret);
6251}
6252
6253/**
6254 * xmlXPathFreeParserContext:
6255 * @ctxt: the context to free
6256 *
6257 * Free up an xmlXPathParserContext
6258 */
6259void
6260xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6261 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006262 xmlFree(ctxt->valueTab);
6263 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00006264 if (ctxt->comp != NULL) {
6265#ifdef XPATH_STREAMING
6266 if (ctxt->comp->stream != NULL) {
6267 xmlFreePatternList(ctxt->comp->stream);
6268 ctxt->comp->stream = NULL;
6269 }
6270#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006271 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard56de87e2005-02-16 00:22:29 +00006272 }
Owen Taylor3473f882001-02-23 17:55:21 +00006273 xmlFree(ctxt);
6274}
6275
6276/************************************************************************
6277 * *
6278 * The implicit core function library *
6279 * *
6280 ************************************************************************/
6281
Owen Taylor3473f882001-02-23 17:55:21 +00006282/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006283 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00006284 * @node: a node pointer
6285 *
6286 * Function computing the beginning of the string value of the node,
6287 * used to speed up comparisons
6288 *
6289 * Returns an int usable as a hash
6290 */
6291static unsigned int
6292xmlXPathNodeValHash(xmlNodePtr node) {
6293 int len = 2;
6294 const xmlChar * string = NULL;
6295 xmlNodePtr tmp = NULL;
6296 unsigned int ret = 0;
6297
6298 if (node == NULL)
6299 return(0);
6300
Daniel Veillard9adc0462003-03-24 18:39:54 +00006301 if (node->type == XML_DOCUMENT_NODE) {
6302 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6303 if (tmp == NULL)
6304 node = node->children;
6305 else
6306 node = tmp;
6307
6308 if (node == NULL)
6309 return(0);
6310 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006311
6312 switch (node->type) {
6313 case XML_COMMENT_NODE:
6314 case XML_PI_NODE:
6315 case XML_CDATA_SECTION_NODE:
6316 case XML_TEXT_NODE:
6317 string = node->content;
6318 if (string == NULL)
6319 return(0);
6320 if (string[0] == 0)
6321 return(0);
6322 return(((unsigned int) string[0]) +
6323 (((unsigned int) string[1]) << 8));
6324 case XML_NAMESPACE_DECL:
6325 string = ((xmlNsPtr)node)->href;
6326 if (string == NULL)
6327 return(0);
6328 if (string[0] == 0)
6329 return(0);
6330 return(((unsigned int) string[0]) +
6331 (((unsigned int) string[1]) << 8));
6332 case XML_ATTRIBUTE_NODE:
6333 tmp = ((xmlAttrPtr) node)->children;
6334 break;
6335 case XML_ELEMENT_NODE:
6336 tmp = node->children;
6337 break;
6338 default:
6339 return(0);
6340 }
6341 while (tmp != NULL) {
6342 switch (tmp->type) {
6343 case XML_COMMENT_NODE:
6344 case XML_PI_NODE:
6345 case XML_CDATA_SECTION_NODE:
6346 case XML_TEXT_NODE:
6347 string = tmp->content;
6348 break;
6349 case XML_NAMESPACE_DECL:
6350 string = ((xmlNsPtr)tmp)->href;
6351 break;
6352 default:
6353 break;
6354 }
6355 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006356 if (len == 1) {
6357 return(ret + (((unsigned int) string[0]) << 8));
6358 }
6359 if (string[1] == 0) {
6360 len = 1;
6361 ret = (unsigned int) string[0];
6362 } else {
6363 return(((unsigned int) string[0]) +
6364 (((unsigned int) string[1]) << 8));
6365 }
6366 }
6367 /*
6368 * Skip to next node
6369 */
6370 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6371 if (tmp->children->type != XML_ENTITY_DECL) {
6372 tmp = tmp->children;
6373 continue;
6374 }
6375 }
6376 if (tmp == node)
6377 break;
6378
6379 if (tmp->next != NULL) {
6380 tmp = tmp->next;
6381 continue;
6382 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00006383
Daniel Veillardf06307e2001-07-03 10:35:50 +00006384 do {
6385 tmp = tmp->parent;
6386 if (tmp == NULL)
6387 break;
6388 if (tmp == node) {
6389 tmp = NULL;
6390 break;
6391 }
6392 if (tmp->next != NULL) {
6393 tmp = tmp->next;
6394 break;
6395 }
6396 } while (tmp != NULL);
6397 }
6398 return(ret);
6399}
6400
6401/**
6402 * xmlXPathStringHash:
6403 * @string: a string
6404 *
6405 * Function computing the beginning of the string value of the node,
6406 * used to speed up comparisons
6407 *
6408 * Returns an int usable as a hash
6409 */
6410static unsigned int
6411xmlXPathStringHash(const xmlChar * string) {
6412 if (string == NULL)
6413 return((unsigned int) 0);
6414 if (string[0] == 0)
6415 return(0);
6416 return(((unsigned int) string[0]) +
6417 (((unsigned int) string[1]) << 8));
6418}
6419
6420/**
Owen Taylor3473f882001-02-23 17:55:21 +00006421 * xmlXPathCompareNodeSetFloat:
6422 * @ctxt: the XPath Parser context
6423 * @inf: less than (1) or greater than (0)
6424 * @strict: is the comparison strict
6425 * @arg: the node set
6426 * @f: the value
6427 *
6428 * Implement the compare operation between a nodeset and a number
6429 * @ns < @val (1, 1, ...
6430 * @ns <= @val (1, 0, ...
6431 * @ns > @val (0, 1, ...
6432 * @ns >= @val (0, 0, ...
6433 *
6434 * If one object to be compared is a node-set and the other is a number,
6435 * then the comparison will be true if and only if there is a node in the
6436 * node-set such that the result of performing the comparison on the number
6437 * to be compared and on the result of converting the string-value of that
6438 * node to a number using the number function is true.
6439 *
6440 * Returns 0 or 1 depending on the results of the test.
6441 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006442static int
Owen Taylor3473f882001-02-23 17:55:21 +00006443xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6444 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6445 int i, ret = 0;
6446 xmlNodeSetPtr ns;
6447 xmlChar *str2;
6448
6449 if ((f == NULL) || (arg == NULL) ||
6450 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006451 xmlXPathReleaseObject(ctxt->context, arg);
6452 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006453 return(0);
6454 }
6455 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006456 if (ns != NULL) {
6457 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006458 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006459 if (str2 != NULL) {
6460 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006461 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006462 xmlFree(str2);
6463 xmlXPathNumberFunction(ctxt, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006464 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006465 ret = xmlXPathCompareValues(ctxt, inf, strict);
6466 if (ret)
6467 break;
6468 }
6469 }
Owen Taylor3473f882001-02-23 17:55:21 +00006470 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006471 xmlXPathReleaseObject(ctxt->context, arg);
6472 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006473 return(ret);
6474}
6475
6476/**
6477 * xmlXPathCompareNodeSetString:
6478 * @ctxt: the XPath Parser context
6479 * @inf: less than (1) or greater than (0)
6480 * @strict: is the comparison strict
6481 * @arg: the node set
6482 * @s: the value
6483 *
6484 * Implement the compare operation between a nodeset and a string
6485 * @ns < @val (1, 1, ...
6486 * @ns <= @val (1, 0, ...
6487 * @ns > @val (0, 1, ...
6488 * @ns >= @val (0, 0, ...
6489 *
6490 * If one object to be compared is a node-set and the other is a string,
6491 * then the comparison will be true if and only if there is a node in
6492 * the node-set such that the result of performing the comparison on the
6493 * string-value of the node and the other string is true.
6494 *
6495 * Returns 0 or 1 depending on the results of the test.
6496 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006497static int
Owen Taylor3473f882001-02-23 17:55:21 +00006498xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6499 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6500 int i, ret = 0;
6501 xmlNodeSetPtr ns;
6502 xmlChar *str2;
6503
6504 if ((s == NULL) || (arg == NULL) ||
6505 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006506 xmlXPathReleaseObject(ctxt->context, arg);
6507 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006508 return(0);
6509 }
6510 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006511 if (ns != NULL) {
6512 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006513 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006514 if (str2 != NULL) {
6515 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006516 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006517 xmlFree(str2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006518 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006519 ret = xmlXPathCompareValues(ctxt, inf, strict);
6520 if (ret)
6521 break;
6522 }
6523 }
Owen Taylor3473f882001-02-23 17:55:21 +00006524 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006525 xmlXPathReleaseObject(ctxt->context, arg);
6526 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006527 return(ret);
6528}
6529
6530/**
6531 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006532 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00006533 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006534 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00006535 * @arg2: the second node set object
6536 *
6537 * Implement the compare operation on nodesets:
6538 *
6539 * If both objects to be compared are node-sets, then the comparison
6540 * will be true if and only if there is a node in the first node-set
6541 * and a node in the second node-set such that the result of performing
Daniel Veillard45490ae2008-07-29 09:13:19 +00006542 * the comparison on the string-values of the two nodes is true.
Owen Taylor3473f882001-02-23 17:55:21 +00006543 * ....
6544 * When neither object to be compared is a node-set and the operator
6545 * is <=, <, >= or >, then the objects are compared by converting both
6546 * objects to numbers and comparing the numbers according to IEEE 754.
6547 * ....
6548 * The number function converts its argument to a number as follows:
6549 * - a string that consists of optional whitespace followed by an
6550 * optional minus sign followed by a Number followed by whitespace
6551 * is converted to the IEEE 754 number that is nearest (according
6552 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6553 * represented by the string; any other string is converted to NaN
6554 *
6555 * Conclusion all nodes need to be converted first to their string value
Daniel Veillard45490ae2008-07-29 09:13:19 +00006556 * and then the comparison must be done when possible
Owen Taylor3473f882001-02-23 17:55:21 +00006557 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006558static int
6559xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00006560 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6561 int i, j, init = 0;
6562 double val1;
6563 double *values2;
6564 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006565 xmlNodeSetPtr ns1;
6566 xmlNodeSetPtr ns2;
6567
6568 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006569 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6570 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006571 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006572 }
Owen Taylor3473f882001-02-23 17:55:21 +00006573 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006574 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6575 xmlXPathFreeObject(arg1);
6576 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006577 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006578 }
Owen Taylor3473f882001-02-23 17:55:21 +00006579
6580 ns1 = arg1->nodesetval;
6581 ns2 = arg2->nodesetval;
6582
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006583 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006584 xmlXPathFreeObject(arg1);
6585 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006586 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006587 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006588 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006589 xmlXPathFreeObject(arg1);
6590 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006591 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006592 }
Owen Taylor3473f882001-02-23 17:55:21 +00006593
6594 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6595 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006596 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00006597 xmlXPathFreeObject(arg1);
6598 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006599 return(0);
6600 }
6601 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006602 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00006603 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00006604 continue;
6605 for (j = 0;j < ns2->nodeNr;j++) {
6606 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006607 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00006608 }
Daniel Veillardcda96922001-08-21 10:56:31 +00006609 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00006610 continue;
Daniel Veillard45490ae2008-07-29 09:13:19 +00006611 if (inf && strict)
Owen Taylor3473f882001-02-23 17:55:21 +00006612 ret = (val1 < values2[j]);
6613 else if (inf && !strict)
6614 ret = (val1 <= values2[j]);
6615 else if (!inf && strict)
6616 ret = (val1 > values2[j]);
6617 else if (!inf && !strict)
6618 ret = (val1 >= values2[j]);
6619 if (ret)
6620 break;
6621 }
6622 if (ret)
6623 break;
6624 init = 1;
6625 }
6626 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006627 xmlXPathFreeObject(arg1);
6628 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006629 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006630}
6631
6632/**
6633 * xmlXPathCompareNodeSetValue:
6634 * @ctxt: the XPath Parser context
6635 * @inf: less than (1) or greater than (0)
6636 * @strict: is the comparison strict
6637 * @arg: the node set
6638 * @val: the value
6639 *
6640 * Implement the compare operation between a nodeset and a value
6641 * @ns < @val (1, 1, ...
6642 * @ns <= @val (1, 0, ...
6643 * @ns > @val (0, 1, ...
6644 * @ns >= @val (0, 0, ...
6645 *
6646 * If one object to be compared is a node-set and the other is a boolean,
6647 * then the comparison will be true if and only if the result of performing
6648 * the comparison on the boolean and on the result of converting
6649 * the node-set to a boolean using the boolean function is true.
6650 *
6651 * Returns 0 or 1 depending on the results of the test.
6652 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006653static int
Owen Taylor3473f882001-02-23 17:55:21 +00006654xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6655 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6656 if ((val == NULL) || (arg == NULL) ||
6657 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6658 return(0);
6659
6660 switch(val->type) {
6661 case XPATH_NUMBER:
6662 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6663 case XPATH_NODESET:
6664 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006665 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00006666 case XPATH_STRING:
6667 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6668 case XPATH_BOOLEAN:
6669 valuePush(ctxt, arg);
6670 xmlXPathBooleanFunction(ctxt, 1);
6671 valuePush(ctxt, val);
6672 return(xmlXPathCompareValues(ctxt, inf, strict));
6673 default:
6674 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00006675 }
6676 return(0);
6677}
6678
6679/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006680 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00006681 * @arg: the nodeset object argument
6682 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00006683 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006684 *
6685 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6686 * If one object to be compared is a node-set and the other is a string,
6687 * then the comparison will be true if and only if there is a node in
6688 * the node-set such that the result of performing the comparison on the
6689 * string-value of the node and the other string is true.
6690 *
6691 * Returns 0 or 1 depending on the results of the test.
6692 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006693static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006694xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006695{
Owen Taylor3473f882001-02-23 17:55:21 +00006696 int i;
6697 xmlNodeSetPtr ns;
6698 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006699 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00006700
6701 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00006702 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6703 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006704 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00006705 /*
6706 * A NULL nodeset compared with a string is always false
6707 * (since there is no node equal, and no node not equal)
6708 */
6709 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00006710 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00006711 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006712 for (i = 0; i < ns->nodeNr; i++) {
6713 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6714 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6715 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6716 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006717 if (neq)
6718 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006719 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00006720 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6721 if (neq)
6722 continue;
6723 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006724 } else if (neq) {
6725 if (str2 != NULL)
6726 xmlFree(str2);
6727 return (1);
6728 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006729 if (str2 != NULL)
6730 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006731 } else if (neq)
6732 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00006733 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006734 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006735}
6736
6737/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006738 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00006739 * @arg: the nodeset object argument
6740 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00006741 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006742 *
6743 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6744 * If one object to be compared is a node-set and the other is a number,
6745 * then the comparison will be true if and only if there is a node in
6746 * the node-set such that the result of performing the comparison on the
6747 * number to be compared and on the result of converting the string-value
6748 * of that node to a number using the number function is true.
6749 *
6750 * Returns 0 or 1 depending on the results of the test.
6751 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006752static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006753xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6754 xmlXPathObjectPtr arg, double f, int neq) {
6755 int i, ret=0;
6756 xmlNodeSetPtr ns;
6757 xmlChar *str2;
6758 xmlXPathObjectPtr val;
6759 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00006760
6761 if ((arg == NULL) ||
6762 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6763 return(0);
6764
William M. Brack0c022ad2002-07-12 00:56:01 +00006765 ns = arg->nodesetval;
6766 if (ns != NULL) {
6767 for (i=0;i<ns->nodeNr;i++) {
6768 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6769 if (str2 != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006770 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
William M. Brack0c022ad2002-07-12 00:56:01 +00006771 xmlFree(str2);
6772 xmlXPathNumberFunction(ctxt, 1);
6773 val = valuePop(ctxt);
6774 v = val->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006775 xmlXPathReleaseObject(ctxt->context, val);
William M. Brack0c022ad2002-07-12 00:56:01 +00006776 if (!xmlXPathIsNaN(v)) {
6777 if ((!neq) && (v==f)) {
6778 ret = 1;
6779 break;
6780 } else if ((neq) && (v!=f)) {
6781 ret = 1;
6782 break;
6783 }
William M. Brack32f0f712005-07-14 07:00:33 +00006784 } else { /* NaN is unequal to any value */
6785 if (neq)
6786 ret = 1;
William M. Brack0c022ad2002-07-12 00:56:01 +00006787 }
6788 }
6789 }
6790 }
6791
6792 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006793}
6794
6795
6796/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006797 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00006798 * @arg1: first nodeset object argument
6799 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00006800 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006801 *
William M. Brack0c022ad2002-07-12 00:56:01 +00006802 * Implement the equal / not equal operation on XPath nodesets:
6803 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00006804 * If both objects to be compared are node-sets, then the comparison
6805 * will be true if and only if there is a node in the first node-set and
6806 * a node in the second node-set such that the result of performing the
6807 * comparison on the string-values of the two nodes is true.
6808 *
6809 * (needless to say, this is a costly operation)
6810 *
6811 * Returns 0 or 1 depending on the results of the test.
6812 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006813static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006814xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00006815 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006816 unsigned int *hashs1;
6817 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00006818 xmlChar **values1;
6819 xmlChar **values2;
6820 int ret = 0;
6821 xmlNodeSetPtr ns1;
6822 xmlNodeSetPtr ns2;
6823
6824 if ((arg1 == NULL) ||
6825 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6826 return(0);
6827 if ((arg2 == NULL) ||
6828 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6829 return(0);
6830
6831 ns1 = arg1->nodesetval;
6832 ns2 = arg2->nodesetval;
6833
Daniel Veillard911f49a2001-04-07 15:39:35 +00006834 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006835 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006836 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006837 return(0);
6838
6839 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00006840 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00006841 */
William M. Brack0c022ad2002-07-12 00:56:01 +00006842 if (neq == 0)
6843 for (i = 0;i < ns1->nodeNr;i++)
6844 for (j = 0;j < ns2->nodeNr;j++)
6845 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6846 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006847
6848 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006849 if (values1 == NULL) {
6850 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006851 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006852 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006853 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6854 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006855 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006856 xmlFree(values1);
6857 return(0);
6858 }
Owen Taylor3473f882001-02-23 17:55:21 +00006859 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6860 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6861 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006862 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006863 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00006864 xmlFree(values1);
6865 return(0);
6866 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006867 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6868 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006869 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006870 xmlFree(hashs1);
6871 xmlFree(values1);
6872 xmlFree(values2);
6873 return(0);
6874 }
Owen Taylor3473f882001-02-23 17:55:21 +00006875 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6876 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006877 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006878 for (j = 0;j < ns2->nodeNr;j++) {
6879 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006880 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006881 if (hashs1[i] != hashs2[j]) {
6882 if (neq) {
6883 ret = 1;
6884 break;
6885 }
6886 }
6887 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006888 if (values1[i] == NULL)
6889 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6890 if (values2[j] == NULL)
6891 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006892 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006893 if (ret)
6894 break;
6895 }
Owen Taylor3473f882001-02-23 17:55:21 +00006896 }
6897 if (ret)
6898 break;
6899 }
6900 for (i = 0;i < ns1->nodeNr;i++)
6901 if (values1[i] != NULL)
6902 xmlFree(values1[i]);
6903 for (j = 0;j < ns2->nodeNr;j++)
6904 if (values2[j] != NULL)
6905 xmlFree(values2[j]);
6906 xmlFree(values1);
6907 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006908 xmlFree(hashs1);
6909 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00006910 return(ret);
6911}
6912
William M. Brack0c022ad2002-07-12 00:56:01 +00006913static int
6914xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6915 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00006916 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00006917 /*
6918 *At this point we are assured neither arg1 nor arg2
6919 *is a nodeset, so we can just pick the appropriate routine.
6920 */
Owen Taylor3473f882001-02-23 17:55:21 +00006921 switch (arg1->type) {
6922 case XPATH_UNDEFINED:
6923#ifdef DEBUG_EXPR
6924 xmlGenericError(xmlGenericErrorContext,
6925 "Equal: undefined\n");
6926#endif
6927 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006928 case XPATH_BOOLEAN:
6929 switch (arg2->type) {
6930 case XPATH_UNDEFINED:
6931#ifdef DEBUG_EXPR
6932 xmlGenericError(xmlGenericErrorContext,
6933 "Equal: undefined\n");
6934#endif
6935 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006936 case XPATH_BOOLEAN:
6937#ifdef DEBUG_EXPR
6938 xmlGenericError(xmlGenericErrorContext,
6939 "Equal: %d boolean %d \n",
6940 arg1->boolval, arg2->boolval);
6941#endif
6942 ret = (arg1->boolval == arg2->boolval);
6943 break;
6944 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00006945 ret = (arg1->boolval ==
6946 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006947 break;
6948 case XPATH_STRING:
6949 if ((arg2->stringval == NULL) ||
6950 (arg2->stringval[0] == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00006951 else
Owen Taylor3473f882001-02-23 17:55:21 +00006952 ret = 1;
6953 ret = (arg1->boolval == ret);
6954 break;
6955 case XPATH_USERS:
6956 case XPATH_POINT:
6957 case XPATH_RANGE:
6958 case XPATH_LOCATIONSET:
6959 TODO
6960 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006961 case XPATH_NODESET:
6962 case XPATH_XSLT_TREE:
6963 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006964 }
6965 break;
6966 case XPATH_NUMBER:
6967 switch (arg2->type) {
6968 case XPATH_UNDEFINED:
6969#ifdef DEBUG_EXPR
6970 xmlGenericError(xmlGenericErrorContext,
6971 "Equal: undefined\n");
6972#endif
6973 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006974 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00006975 ret = (arg2->boolval==
6976 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006977 break;
6978 case XPATH_STRING:
6979 valuePush(ctxt, arg2);
6980 xmlXPathNumberFunction(ctxt, 1);
6981 arg2 = valuePop(ctxt);
6982 /* no break on purpose */
6983 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006984 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00006985 if (xmlXPathIsNaN(arg1->floatval) ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00006986 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00006987 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006988 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6989 if (xmlXPathIsInf(arg2->floatval) == 1)
6990 ret = 1;
6991 else
6992 ret = 0;
6993 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6994 if (xmlXPathIsInf(arg2->floatval) == -1)
6995 ret = 1;
6996 else
6997 ret = 0;
6998 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6999 if (xmlXPathIsInf(arg1->floatval) == 1)
7000 ret = 1;
7001 else
7002 ret = 0;
7003 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7004 if (xmlXPathIsInf(arg1->floatval) == -1)
7005 ret = 1;
7006 else
7007 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007008 } else {
7009 ret = (arg1->floatval == arg2->floatval);
7010 }
Owen Taylor3473f882001-02-23 17:55:21 +00007011 break;
7012 case XPATH_USERS:
7013 case XPATH_POINT:
7014 case XPATH_RANGE:
7015 case XPATH_LOCATIONSET:
7016 TODO
7017 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007018 case XPATH_NODESET:
7019 case XPATH_XSLT_TREE:
7020 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007021 }
7022 break;
7023 case XPATH_STRING:
7024 switch (arg2->type) {
7025 case XPATH_UNDEFINED:
7026#ifdef DEBUG_EXPR
7027 xmlGenericError(xmlGenericErrorContext,
7028 "Equal: undefined\n");
7029#endif
7030 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007031 case XPATH_BOOLEAN:
7032 if ((arg1->stringval == NULL) ||
7033 (arg1->stringval[0] == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007034 else
Owen Taylor3473f882001-02-23 17:55:21 +00007035 ret = 1;
7036 ret = (arg2->boolval == ret);
7037 break;
7038 case XPATH_STRING:
7039 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7040 break;
7041 case XPATH_NUMBER:
7042 valuePush(ctxt, arg1);
7043 xmlXPathNumberFunction(ctxt, 1);
7044 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007045 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00007046 if (xmlXPathIsNaN(arg1->floatval) ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00007047 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00007048 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007049 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7050 if (xmlXPathIsInf(arg2->floatval) == 1)
7051 ret = 1;
7052 else
7053 ret = 0;
7054 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7055 if (xmlXPathIsInf(arg2->floatval) == -1)
7056 ret = 1;
7057 else
7058 ret = 0;
7059 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7060 if (xmlXPathIsInf(arg1->floatval) == 1)
7061 ret = 1;
7062 else
7063 ret = 0;
7064 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7065 if (xmlXPathIsInf(arg1->floatval) == -1)
7066 ret = 1;
7067 else
7068 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007069 } else {
7070 ret = (arg1->floatval == arg2->floatval);
7071 }
Owen Taylor3473f882001-02-23 17:55:21 +00007072 break;
7073 case XPATH_USERS:
7074 case XPATH_POINT:
7075 case XPATH_RANGE:
7076 case XPATH_LOCATIONSET:
7077 TODO
7078 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007079 case XPATH_NODESET:
7080 case XPATH_XSLT_TREE:
7081 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007082 }
7083 break;
7084 case XPATH_USERS:
7085 case XPATH_POINT:
7086 case XPATH_RANGE:
7087 case XPATH_LOCATIONSET:
7088 TODO
7089 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007090 case XPATH_NODESET:
7091 case XPATH_XSLT_TREE:
7092 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007093 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007094 xmlXPathReleaseObject(ctxt->context, arg1);
7095 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007096 return(ret);
7097}
7098
William M. Brack0c022ad2002-07-12 00:56:01 +00007099/**
7100 * xmlXPathEqualValues:
7101 * @ctxt: the XPath Parser context
7102 *
7103 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7104 *
7105 * Returns 0 or 1 depending on the results of the test.
7106 */
7107int
7108xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7109 xmlXPathObjectPtr arg1, arg2, argtmp;
7110 int ret = 0;
7111
Daniel Veillard6128c012004-11-08 17:16:15 +00007112 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007113 arg2 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007114 arg1 = valuePop(ctxt);
7115 if ((arg1 == NULL) || (arg2 == NULL)) {
7116 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007117 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007118 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007119 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007120 XP_ERROR0(XPATH_INVALID_OPERAND);
7121 }
7122
7123 if (arg1 == arg2) {
7124#ifdef DEBUG_EXPR
7125 xmlGenericError(xmlGenericErrorContext,
7126 "Equal: by pointer\n");
7127#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00007128 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007129 return(1);
7130 }
7131
7132 /*
7133 *If either argument is a nodeset, it's a 'special case'
7134 */
7135 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7136 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7137 /*
7138 *Hack it to assure arg1 is the nodeset
7139 */
7140 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7141 argtmp = arg2;
7142 arg2 = arg1;
7143 arg1 = argtmp;
7144 }
7145 switch (arg2->type) {
7146 case XPATH_UNDEFINED:
7147#ifdef DEBUG_EXPR
7148 xmlGenericError(xmlGenericErrorContext,
7149 "Equal: undefined\n");
7150#endif
7151 break;
7152 case XPATH_NODESET:
7153 case XPATH_XSLT_TREE:
7154 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7155 break;
7156 case XPATH_BOOLEAN:
7157 if ((arg1->nodesetval == NULL) ||
7158 (arg1->nodesetval->nodeNr == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007159 else
William M. Brack0c022ad2002-07-12 00:56:01 +00007160 ret = 1;
7161 ret = (ret == arg2->boolval);
7162 break;
7163 case XPATH_NUMBER:
7164 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7165 break;
7166 case XPATH_STRING:
7167 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7168 break;
7169 case XPATH_USERS:
7170 case XPATH_POINT:
7171 case XPATH_RANGE:
7172 case XPATH_LOCATIONSET:
7173 TODO
7174 break;
7175 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007176 xmlXPathReleaseObject(ctxt->context, arg1);
7177 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007178 return(ret);
7179 }
7180
7181 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7182}
7183
7184/**
7185 * xmlXPathNotEqualValues:
7186 * @ctxt: the XPath Parser context
7187 *
7188 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7189 *
7190 * Returns 0 or 1 depending on the results of the test.
7191 */
7192int
7193xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7194 xmlXPathObjectPtr arg1, arg2, argtmp;
7195 int ret = 0;
7196
Daniel Veillard6128c012004-11-08 17:16:15 +00007197 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007198 arg2 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007199 arg1 = valuePop(ctxt);
7200 if ((arg1 == NULL) || (arg2 == NULL)) {
7201 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007202 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007203 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007204 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007205 XP_ERROR0(XPATH_INVALID_OPERAND);
7206 }
7207
7208 if (arg1 == arg2) {
7209#ifdef DEBUG_EXPR
7210 xmlGenericError(xmlGenericErrorContext,
7211 "NotEqual: by pointer\n");
7212#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007213 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007214 return(0);
7215 }
7216
7217 /*
7218 *If either argument is a nodeset, it's a 'special case'
7219 */
7220 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7221 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7222 /*
7223 *Hack it to assure arg1 is the nodeset
7224 */
7225 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7226 argtmp = arg2;
7227 arg2 = arg1;
7228 arg1 = argtmp;
7229 }
7230 switch (arg2->type) {
7231 case XPATH_UNDEFINED:
7232#ifdef DEBUG_EXPR
7233 xmlGenericError(xmlGenericErrorContext,
7234 "NotEqual: undefined\n");
7235#endif
7236 break;
7237 case XPATH_NODESET:
7238 case XPATH_XSLT_TREE:
7239 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7240 break;
7241 case XPATH_BOOLEAN:
7242 if ((arg1->nodesetval == NULL) ||
7243 (arg1->nodesetval->nodeNr == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007244 else
William M. Brack0c022ad2002-07-12 00:56:01 +00007245 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00007246 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00007247 break;
7248 case XPATH_NUMBER:
7249 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7250 break;
7251 case XPATH_STRING:
7252 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7253 break;
7254 case XPATH_USERS:
7255 case XPATH_POINT:
7256 case XPATH_RANGE:
7257 case XPATH_LOCATIONSET:
7258 TODO
7259 break;
7260 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007261 xmlXPathReleaseObject(ctxt->context, arg1);
7262 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007263 return(ret);
7264 }
7265
7266 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7267}
Owen Taylor3473f882001-02-23 17:55:21 +00007268
7269/**
7270 * xmlXPathCompareValues:
7271 * @ctxt: the XPath Parser context
7272 * @inf: less than (1) or greater than (0)
7273 * @strict: is the comparison strict
7274 *
Daniel Veillard45490ae2008-07-29 09:13:19 +00007275 * Implement the compare operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007276 * @arg1 < @arg2 (1, 1, ...
7277 * @arg1 <= @arg2 (1, 0, ...
7278 * @arg1 > @arg2 (0, 1, ...
7279 * @arg1 >= @arg2 (0, 0, ...
7280 *
7281 * When neither object to be compared is a node-set and the operator is
7282 * <=, <, >=, >, then the objects are compared by converted both objects
7283 * to numbers and comparing the numbers according to IEEE 754. The <
7284 * comparison will be true if and only if the first number is less than the
7285 * second number. The <= comparison will be true if and only if the first
7286 * number is less than or equal to the second number. The > comparison
7287 * will be true if and only if the first number is greater than the second
7288 * number. The >= comparison will be true if and only if the first number
7289 * is greater than or equal to the second number.
7290 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007291 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00007292 */
7293int
7294xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007295 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007296 xmlXPathObjectPtr arg1, arg2;
7297
Daniel Veillard6128c012004-11-08 17:16:15 +00007298 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007299 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007300 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007301 if ((arg1 == NULL) || (arg2 == NULL)) {
7302 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007303 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007304 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007305 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007306 XP_ERROR0(XPATH_INVALID_OPERAND);
7307 }
7308
William M. Brack0c022ad2002-07-12 00:56:01 +00007309 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7310 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
William M. Brackd6e347e2005-04-15 01:34:41 +00007311 /*
7312 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7313 * are not freed from within this routine; they will be freed from the
7314 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7315 */
William M. Brack0c022ad2002-07-12 00:56:01 +00007316 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7317 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007318 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007319 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00007320 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007321 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7322 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007323 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007324 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7325 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00007326 }
7327 }
7328 return(ret);
7329 }
7330
7331 if (arg1->type != XPATH_NUMBER) {
7332 valuePush(ctxt, arg1);
7333 xmlXPathNumberFunction(ctxt, 1);
7334 arg1 = valuePop(ctxt);
7335 }
7336 if (arg1->type != XPATH_NUMBER) {
7337 xmlXPathFreeObject(arg1);
7338 xmlXPathFreeObject(arg2);
7339 XP_ERROR0(XPATH_INVALID_OPERAND);
7340 }
7341 if (arg2->type != XPATH_NUMBER) {
7342 valuePush(ctxt, arg2);
7343 xmlXPathNumberFunction(ctxt, 1);
7344 arg2 = valuePop(ctxt);
7345 }
7346 if (arg2->type != XPATH_NUMBER) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007347 xmlXPathReleaseObject(ctxt->context, arg1);
7348 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007349 XP_ERROR0(XPATH_INVALID_OPERAND);
7350 }
7351 /*
7352 * Add tests for infinity and nan
7353 * => feedback on 3.4 for Inf and NaN
7354 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007355 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00007356 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007357 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007358 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007359 arg1i=xmlXPathIsInf(arg1->floatval);
7360 arg2i=xmlXPathIsInf(arg2->floatval);
7361 if (inf && strict) {
7362 if ((arg1i == -1 && arg2i != -1) ||
7363 (arg2i == 1 && arg1i != 1)) {
7364 ret = 1;
7365 } else if (arg1i == 0 && arg2i == 0) {
7366 ret = (arg1->floatval < arg2->floatval);
7367 } else {
7368 ret = 0;
7369 }
7370 }
7371 else if (inf && !strict) {
7372 if (arg1i == -1 || arg2i == 1) {
7373 ret = 1;
7374 } else if (arg1i == 0 && arg2i == 0) {
7375 ret = (arg1->floatval <= arg2->floatval);
7376 } else {
7377 ret = 0;
7378 }
7379 }
7380 else if (!inf && strict) {
7381 if ((arg1i == 1 && arg2i != 1) ||
7382 (arg2i == -1 && arg1i != -1)) {
7383 ret = 1;
7384 } else if (arg1i == 0 && arg2i == 0) {
7385 ret = (arg1->floatval > arg2->floatval);
7386 } else {
7387 ret = 0;
7388 }
7389 }
7390 else if (!inf && !strict) {
7391 if (arg1i == 1 || arg2i == -1) {
7392 ret = 1;
7393 } else if (arg1i == 0 && arg2i == 0) {
7394 ret = (arg1->floatval >= arg2->floatval);
7395 } else {
7396 ret = 0;
7397 }
7398 }
Daniel Veillard21458c82002-03-27 16:12:22 +00007399 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007400 xmlXPathReleaseObject(ctxt->context, arg1);
7401 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007402 return(ret);
7403}
7404
7405/**
7406 * xmlXPathValueFlipSign:
7407 * @ctxt: the XPath Parser context
7408 *
7409 * Implement the unary - operation on an XPath object
7410 * The numeric operators convert their operands to numbers as if
7411 * by calling the number function.
7412 */
7413void
7414xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007415 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007416 CAST_TO_NUMBER;
7417 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007418 if (xmlXPathIsNaN(ctxt->value->floatval))
7419 ctxt->value->floatval=xmlXPathNAN;
7420 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7421 ctxt->value->floatval=xmlXPathNINF;
7422 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7423 ctxt->value->floatval=xmlXPathPINF;
7424 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007425 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7426 ctxt->value->floatval = xmlXPathNZERO;
7427 else
7428 ctxt->value->floatval = 0;
7429 }
7430 else
7431 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00007432}
7433
7434/**
7435 * xmlXPathAddValues:
7436 * @ctxt: the XPath Parser context
7437 *
7438 * Implement the add operation on XPath objects:
7439 * The numeric operators convert their operands to numbers as if
7440 * by calling the number function.
7441 */
7442void
7443xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7444 xmlXPathObjectPtr arg;
7445 double val;
7446
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007447 arg = valuePop(ctxt);
7448 if (arg == NULL)
7449 XP_ERROR(XPATH_INVALID_OPERAND);
7450 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007451 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007452 CAST_TO_NUMBER;
7453 CHECK_TYPE(XPATH_NUMBER);
7454 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00007455}
7456
7457/**
7458 * xmlXPathSubValues:
7459 * @ctxt: the XPath Parser context
7460 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007461 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007462 * The numeric operators convert their operands to numbers as if
7463 * by calling the number function.
7464 */
7465void
7466xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7467 xmlXPathObjectPtr arg;
7468 double val;
7469
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007470 arg = valuePop(ctxt);
7471 if (arg == NULL)
7472 XP_ERROR(XPATH_INVALID_OPERAND);
7473 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007474 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007475 CAST_TO_NUMBER;
7476 CHECK_TYPE(XPATH_NUMBER);
7477 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007478}
7479
7480/**
7481 * xmlXPathMultValues:
7482 * @ctxt: the XPath Parser context
7483 *
7484 * Implement the multiply operation on XPath objects:
7485 * The numeric operators convert their operands to numbers as if
7486 * by calling the number function.
7487 */
7488void
7489xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7490 xmlXPathObjectPtr arg;
7491 double val;
7492
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007493 arg = valuePop(ctxt);
7494 if (arg == NULL)
7495 XP_ERROR(XPATH_INVALID_OPERAND);
7496 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007497 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007498 CAST_TO_NUMBER;
7499 CHECK_TYPE(XPATH_NUMBER);
7500 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007501}
7502
7503/**
7504 * xmlXPathDivValues:
7505 * @ctxt: the XPath Parser context
7506 *
7507 * Implement the div operation on XPath objects @arg1 / @arg2:
7508 * The numeric operators convert their operands to numbers as if
7509 * by calling the number function.
7510 */
7511void
7512xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7513 xmlXPathObjectPtr arg;
7514 double val;
7515
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007516 arg = valuePop(ctxt);
7517 if (arg == NULL)
7518 XP_ERROR(XPATH_INVALID_OPERAND);
7519 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007520 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007521 CAST_TO_NUMBER;
7522 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007523 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7524 ctxt->value->floatval = xmlXPathNAN;
7525 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007526 if (ctxt->value->floatval == 0)
7527 ctxt->value->floatval = xmlXPathNAN;
7528 else if (ctxt->value->floatval > 0)
7529 ctxt->value->floatval = xmlXPathNINF;
7530 else if (ctxt->value->floatval < 0)
7531 ctxt->value->floatval = xmlXPathPINF;
7532 }
7533 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007534 if (ctxt->value->floatval == 0)
7535 ctxt->value->floatval = xmlXPathNAN;
7536 else if (ctxt->value->floatval > 0)
7537 ctxt->value->floatval = xmlXPathPINF;
7538 else if (ctxt->value->floatval < 0)
7539 ctxt->value->floatval = xmlXPathNINF;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007540 } else
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007541 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007542}
7543
7544/**
7545 * xmlXPathModValues:
7546 * @ctxt: the XPath Parser context
7547 *
7548 * Implement the mod operation on XPath objects: @arg1 / @arg2
7549 * The numeric operators convert their operands to numbers as if
7550 * by calling the number function.
7551 */
7552void
7553xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7554 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00007555 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00007556
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007557 arg = valuePop(ctxt);
7558 if (arg == NULL)
7559 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007560 arg2 = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007561 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007562 CAST_TO_NUMBER;
7563 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007564 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00007565 if (arg2 == 0)
7566 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007567 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00007568 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007569 }
Owen Taylor3473f882001-02-23 17:55:21 +00007570}
7571
7572/************************************************************************
7573 * *
7574 * The traversal functions *
7575 * *
7576 ************************************************************************/
7577
Owen Taylor3473f882001-02-23 17:55:21 +00007578/*
7579 * A traversal function enumerates nodes along an axis.
7580 * Initially it must be called with NULL, and it indicates
7581 * termination on the axis by returning NULL.
7582 */
7583typedef xmlNodePtr (*xmlXPathTraversalFunction)
7584 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7585
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007586/*
7587 * xmlXPathTraversalFunctionExt:
7588 * A traversal function enumerates nodes along an axis.
7589 * Initially it must be called with NULL, and it indicates
7590 * termination on the axis by returning NULL.
7591 * The context node of the traversal is specified via @contextNode.
7592 */
7593typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7594 (xmlNodePtr cur, xmlNodePtr contextNode);
7595
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00007596/*
7597 * xmlXPathNodeSetMergeFunction:
7598 * Used for merging node sets in xmlXPathCollectAndTest().
7599 */
7600typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7601 (xmlNodeSetPtr, xmlNodeSetPtr, int);
7602
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007603
Owen Taylor3473f882001-02-23 17:55:21 +00007604/**
7605 * xmlXPathNextSelf:
7606 * @ctxt: the XPath Parser context
7607 * @cur: the current node in the traversal
7608 *
7609 * Traversal function for the "self" direction
7610 * The self axis contains just the context node itself
7611 *
7612 * Returns the next element following that axis
7613 */
7614xmlNodePtr
7615xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007616 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007617 if (cur == NULL)
7618 return(ctxt->context->node);
7619 return(NULL);
7620}
7621
7622/**
7623 * xmlXPathNextChild:
7624 * @ctxt: the XPath Parser context
7625 * @cur: the current node in the traversal
7626 *
7627 * Traversal function for the "child" direction
7628 * The child axis contains the children of the context node in document order.
7629 *
7630 * Returns the next element following that axis
7631 */
7632xmlNodePtr
7633xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007634 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007635 if (cur == NULL) {
7636 if (ctxt->context->node == NULL) return(NULL);
7637 switch (ctxt->context->node->type) {
7638 case XML_ELEMENT_NODE:
7639 case XML_TEXT_NODE:
7640 case XML_CDATA_SECTION_NODE:
7641 case XML_ENTITY_REF_NODE:
7642 case XML_ENTITY_NODE:
7643 case XML_PI_NODE:
7644 case XML_COMMENT_NODE:
7645 case XML_NOTATION_NODE:
7646 case XML_DTD_NODE:
7647 return(ctxt->context->node->children);
7648 case XML_DOCUMENT_NODE:
7649 case XML_DOCUMENT_TYPE_NODE:
7650 case XML_DOCUMENT_FRAG_NODE:
7651 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007652#ifdef LIBXML_DOCB_ENABLED
7653 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007654#endif
7655 return(((xmlDocPtr) ctxt->context->node)->children);
7656 case XML_ELEMENT_DECL:
7657 case XML_ATTRIBUTE_DECL:
7658 case XML_ENTITY_DECL:
7659 case XML_ATTRIBUTE_NODE:
7660 case XML_NAMESPACE_DECL:
7661 case XML_XINCLUDE_START:
7662 case XML_XINCLUDE_END:
7663 return(NULL);
7664 }
7665 return(NULL);
7666 }
7667 if ((cur->type == XML_DOCUMENT_NODE) ||
7668 (cur->type == XML_HTML_DOCUMENT_NODE))
7669 return(NULL);
7670 return(cur->next);
7671}
7672
7673/**
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00007674 * xmlXPathNextChildElement:
7675 * @ctxt: the XPath Parser context
7676 * @cur: the current node in the traversal
7677 *
7678 * Traversal function for the "child" direction and nodes of type element.
7679 * The child axis contains the children of the context node in document order.
7680 *
7681 * Returns the next element following that axis
7682 */
7683static xmlNodePtr
7684xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7685 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7686 if (cur == NULL) {
7687 cur = ctxt->context->node;
7688 if (cur == NULL) return(NULL);
7689 /*
7690 * Get the first element child.
7691 */
7692 switch (cur->type) {
7693 case XML_ELEMENT_NODE:
7694 case XML_DOCUMENT_FRAG_NODE:
7695 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7696 case XML_ENTITY_NODE:
7697 cur = cur->children;
7698 if (cur != NULL) {
7699 if (cur->type == XML_ELEMENT_NODE)
7700 return(cur);
7701 do {
7702 cur = cur->next;
7703 } while ((cur != NULL) &&
7704 (cur->type != XML_ELEMENT_NODE));
7705 return(cur);
7706 }
7707 return(NULL);
7708 case XML_DOCUMENT_NODE:
7709 case XML_HTML_DOCUMENT_NODE:
7710#ifdef LIBXML_DOCB_ENABLED
7711 case XML_DOCB_DOCUMENT_NODE:
7712#endif
7713 return(xmlDocGetRootElement((xmlDocPtr) cur));
7714 default:
7715 return(NULL);
7716 }
7717 return(NULL);
7718 }
7719 /*
7720 * Get the next sibling element node.
7721 */
7722 switch (cur->type) {
7723 case XML_ELEMENT_NODE:
7724 case XML_TEXT_NODE:
7725 case XML_ENTITY_REF_NODE:
7726 case XML_ENTITY_NODE:
7727 case XML_CDATA_SECTION_NODE:
7728 case XML_PI_NODE:
7729 case XML_COMMENT_NODE:
7730 case XML_XINCLUDE_END:
7731 break;
7732 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7733 default:
7734 return(NULL);
7735 }
7736 if (cur->next != NULL) {
7737 if (cur->next->type == XML_ELEMENT_NODE)
7738 return(cur->next);
7739 cur = cur->next;
7740 do {
7741 cur = cur->next;
7742 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7743 return(cur);
7744 }
7745 return(NULL);
7746}
7747
7748/**
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007749 * xmlXPathNextDescendantOrSelfElemParent:
7750 * @ctxt: the XPath Parser context
7751 * @cur: the current node in the traversal
7752 *
7753 * Traversal function for the "descendant-or-self" axis.
7754 * Additionally it returns only nodes which can be parents of
7755 * element nodes.
7756 *
7757 *
7758 * Returns the next element following that axis
7759 */
7760static xmlNodePtr
7761xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7762 xmlNodePtr contextNode)
7763{
7764 if (cur == NULL) {
7765 if (contextNode == NULL)
7766 return(NULL);
7767 switch (contextNode->type) {
7768 case XML_ELEMENT_NODE:
7769 case XML_XINCLUDE_START:
7770 case XML_DOCUMENT_FRAG_NODE:
7771 case XML_DOCUMENT_NODE:
7772#ifdef LIBXML_DOCB_ENABLED
7773 case XML_DOCB_DOCUMENT_NODE:
7774#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00007775 case XML_HTML_DOCUMENT_NODE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007776 return(contextNode);
7777 default:
Daniel Veillard45490ae2008-07-29 09:13:19 +00007778 return(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007779 }
7780 return(NULL);
7781 } else {
7782 xmlNodePtr start = cur;
7783
7784 while (cur != NULL) {
7785 switch (cur->type) {
7786 case XML_ELEMENT_NODE:
7787 /* TODO: OK to have XInclude here? */
7788 case XML_XINCLUDE_START:
Daniel Veillard45490ae2008-07-29 09:13:19 +00007789 case XML_DOCUMENT_FRAG_NODE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007790 if (cur != start)
7791 return(cur);
7792 if (cur->children != NULL) {
7793 cur = cur->children;
7794 continue;
7795 }
7796 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007797 /* Not sure if we need those here. */
7798 case XML_DOCUMENT_NODE:
Daniel Veillard17970a72006-10-26 08:55:47 +00007799#ifdef LIBXML_DOCB_ENABLED
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007800 case XML_DOCB_DOCUMENT_NODE:
7801#endif
7802 case XML_HTML_DOCUMENT_NODE:
7803 if (cur != start)
7804 return(cur);
7805 return(xmlDocGetRootElement((xmlDocPtr) cur));
7806 default:
7807 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007808 }
7809
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007810next_sibling:
7811 if ((cur == NULL) || (cur == contextNode))
Daniel Veillard45490ae2008-07-29 09:13:19 +00007812 return(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007813 if (cur->next != NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00007814 cur = cur->next;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007815 } else {
7816 cur = cur->parent;
7817 goto next_sibling;
7818 }
7819 }
7820 }
7821 return(NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007822}
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007823
7824/**
Owen Taylor3473f882001-02-23 17:55:21 +00007825 * xmlXPathNextDescendant:
7826 * @ctxt: the XPath Parser context
7827 * @cur: the current node in the traversal
7828 *
7829 * Traversal function for the "descendant" direction
7830 * the descendant axis contains the descendants of the context node in document
7831 * order; a descendant is a child or a child of a child and so on.
7832 *
7833 * Returns the next element following that axis
7834 */
7835xmlNodePtr
7836xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007837 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007838 if (cur == NULL) {
7839 if (ctxt->context->node == NULL)
7840 return(NULL);
7841 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7842 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7843 return(NULL);
7844
7845 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7846 return(ctxt->context->doc->children);
7847 return(ctxt->context->node->children);
7848 }
7849
Daniel Veillard3e62adb2012-08-09 14:24:02 +08007850 if (cur->type == XML_NAMESPACE_DECL)
7851 return(NULL);
Daniel Veillard567e1b42001-08-01 15:53:47 +00007852 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007853 /*
7854 * Do not descend on entities declarations
7855 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00007856 if (cur->children->type != XML_ENTITY_DECL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007857 cur = cur->children;
7858 /*
7859 * Skip DTDs
7860 */
7861 if (cur->type != XML_DTD_NODE)
7862 return(cur);
7863 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00007864 }
7865
7866 if (cur == ctxt->context->node) return(NULL);
7867
Daniel Veillard68e9e742002-11-16 15:35:11 +00007868 while (cur->next != NULL) {
7869 cur = cur->next;
7870 if ((cur->type != XML_ENTITY_DECL) &&
7871 (cur->type != XML_DTD_NODE))
7872 return(cur);
7873 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00007874
Owen Taylor3473f882001-02-23 17:55:21 +00007875 do {
7876 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00007877 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00007878 if (cur == ctxt->context->node) return(NULL);
7879 if (cur->next != NULL) {
7880 cur = cur->next;
7881 return(cur);
7882 }
7883 } while (cur != NULL);
7884 return(cur);
7885}
7886
7887/**
7888 * xmlXPathNextDescendantOrSelf:
7889 * @ctxt: the XPath Parser context
7890 * @cur: the current node in the traversal
7891 *
7892 * Traversal function for the "descendant-or-self" direction
7893 * the descendant-or-self axis contains the context node and the descendants
7894 * of the context node in document order; thus the context node is the first
7895 * node on the axis, and the first child of the context node is the second node
7896 * on the axis
7897 *
7898 * Returns the next element following that axis
7899 */
7900xmlNodePtr
7901xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007902 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007903 if (cur == NULL) {
7904 if (ctxt->context->node == NULL)
7905 return(NULL);
7906 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7907 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7908 return(NULL);
7909 return(ctxt->context->node);
7910 }
7911
7912 return(xmlXPathNextDescendant(ctxt, cur));
7913}
7914
7915/**
7916 * xmlXPathNextParent:
7917 * @ctxt: the XPath Parser context
7918 * @cur: the current node in the traversal
7919 *
7920 * Traversal function for the "parent" direction
7921 * The parent axis contains the parent of the context node, if there is one.
7922 *
7923 * Returns the next element following that axis
7924 */
7925xmlNodePtr
7926xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007927 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007928 /*
7929 * the parent of an attribute or namespace node is the element
7930 * to which the attribute or namespace node is attached
7931 * Namespace handling !!!
7932 */
7933 if (cur == NULL) {
7934 if (ctxt->context->node == NULL) return(NULL);
7935 switch (ctxt->context->node->type) {
7936 case XML_ELEMENT_NODE:
7937 case XML_TEXT_NODE:
7938 case XML_CDATA_SECTION_NODE:
7939 case XML_ENTITY_REF_NODE:
7940 case XML_ENTITY_NODE:
7941 case XML_PI_NODE:
7942 case XML_COMMENT_NODE:
7943 case XML_NOTATION_NODE:
7944 case XML_DTD_NODE:
7945 case XML_ELEMENT_DECL:
7946 case XML_ATTRIBUTE_DECL:
7947 case XML_XINCLUDE_START:
7948 case XML_XINCLUDE_END:
7949 case XML_ENTITY_DECL:
7950 if (ctxt->context->node->parent == NULL)
7951 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007952 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007953 ((ctxt->context->node->parent->name[0] == ' ') ||
7954 (xmlStrEqual(ctxt->context->node->parent->name,
7955 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007956 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007957 return(ctxt->context->node->parent);
7958 case XML_ATTRIBUTE_NODE: {
7959 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7960
7961 return(att->parent);
7962 }
7963 case XML_DOCUMENT_NODE:
7964 case XML_DOCUMENT_TYPE_NODE:
7965 case XML_DOCUMENT_FRAG_NODE:
7966 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007967#ifdef LIBXML_DOCB_ENABLED
7968 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007969#endif
7970 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007971 case XML_NAMESPACE_DECL: {
7972 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007973
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007974 if ((ns->next != NULL) &&
7975 (ns->next->type != XML_NAMESPACE_DECL))
7976 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00007977 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007978 }
Owen Taylor3473f882001-02-23 17:55:21 +00007979 }
7980 }
7981 return(NULL);
7982}
7983
7984/**
7985 * xmlXPathNextAncestor:
7986 * @ctxt: the XPath Parser context
7987 * @cur: the current node in the traversal
7988 *
7989 * Traversal function for the "ancestor" direction
7990 * the ancestor axis contains the ancestors of the context node; the ancestors
7991 * of the context node consist of the parent of context node and the parent's
7992 * parent and so on; the nodes are ordered in reverse document order; thus the
7993 * parent is the first node on the axis, and the parent's parent is the second
7994 * node on the axis
7995 *
7996 * Returns the next element following that axis
7997 */
7998xmlNodePtr
7999xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008000 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008001 /*
8002 * the parent of an attribute or namespace node is the element
8003 * to which the attribute or namespace node is attached
8004 * !!!!!!!!!!!!!
8005 */
8006 if (cur == NULL) {
8007 if (ctxt->context->node == NULL) return(NULL);
8008 switch (ctxt->context->node->type) {
8009 case XML_ELEMENT_NODE:
8010 case XML_TEXT_NODE:
8011 case XML_CDATA_SECTION_NODE:
8012 case XML_ENTITY_REF_NODE:
8013 case XML_ENTITY_NODE:
8014 case XML_PI_NODE:
8015 case XML_COMMENT_NODE:
8016 case XML_DTD_NODE:
8017 case XML_ELEMENT_DECL:
8018 case XML_ATTRIBUTE_DECL:
8019 case XML_ENTITY_DECL:
8020 case XML_NOTATION_NODE:
8021 case XML_XINCLUDE_START:
8022 case XML_XINCLUDE_END:
8023 if (ctxt->context->node->parent == NULL)
8024 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008025 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00008026 ((ctxt->context->node->parent->name[0] == ' ') ||
8027 (xmlStrEqual(ctxt->context->node->parent->name,
8028 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008029 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008030 return(ctxt->context->node->parent);
8031 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008032 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00008033
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008034 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00008035 }
8036 case XML_DOCUMENT_NODE:
8037 case XML_DOCUMENT_TYPE_NODE:
8038 case XML_DOCUMENT_FRAG_NODE:
8039 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00008040#ifdef LIBXML_DOCB_ENABLED
8041 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00008042#endif
8043 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008044 case XML_NAMESPACE_DECL: {
8045 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008046
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008047 if ((ns->next != NULL) &&
8048 (ns->next->type != XML_NAMESPACE_DECL))
8049 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00008050 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00008051 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008052 }
Owen Taylor3473f882001-02-23 17:55:21 +00008053 }
8054 return(NULL);
8055 }
8056 if (cur == ctxt->context->doc->children)
8057 return((xmlNodePtr) ctxt->context->doc);
8058 if (cur == (xmlNodePtr) ctxt->context->doc)
8059 return(NULL);
8060 switch (cur->type) {
8061 case XML_ELEMENT_NODE:
8062 case XML_TEXT_NODE:
8063 case XML_CDATA_SECTION_NODE:
8064 case XML_ENTITY_REF_NODE:
8065 case XML_ENTITY_NODE:
8066 case XML_PI_NODE:
8067 case XML_COMMENT_NODE:
8068 case XML_NOTATION_NODE:
8069 case XML_DTD_NODE:
8070 case XML_ELEMENT_DECL:
8071 case XML_ATTRIBUTE_DECL:
8072 case XML_ENTITY_DECL:
8073 case XML_XINCLUDE_START:
8074 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008075 if (cur->parent == NULL)
8076 return(NULL);
8077 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00008078 ((cur->parent->name[0] == ' ') ||
8079 (xmlStrEqual(cur->parent->name,
8080 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008081 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008082 return(cur->parent);
8083 case XML_ATTRIBUTE_NODE: {
8084 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
8085
8086 return(att->parent);
8087 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008088 case XML_NAMESPACE_DECL: {
8089 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008090
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008091 if ((ns->next != NULL) &&
8092 (ns->next->type != XML_NAMESPACE_DECL))
8093 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00008094 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008095 return(NULL);
8096 }
Owen Taylor3473f882001-02-23 17:55:21 +00008097 case XML_DOCUMENT_NODE:
8098 case XML_DOCUMENT_TYPE_NODE:
8099 case XML_DOCUMENT_FRAG_NODE:
8100 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00008101#ifdef LIBXML_DOCB_ENABLED
8102 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00008103#endif
8104 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008105 }
8106 return(NULL);
8107}
8108
8109/**
8110 * xmlXPathNextAncestorOrSelf:
8111 * @ctxt: the XPath Parser context
8112 * @cur: the current node in the traversal
8113 *
8114 * Traversal function for the "ancestor-or-self" direction
8115 * he ancestor-or-self axis contains the context node and ancestors of
8116 * the context node in reverse document order; thus the context node is
8117 * the first node on the axis, and the context node's parent the second;
8118 * parent here is defined the same as with the parent axis.
8119 *
8120 * Returns the next element following that axis
8121 */
8122xmlNodePtr
8123xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008124 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008125 if (cur == NULL)
8126 return(ctxt->context->node);
8127 return(xmlXPathNextAncestor(ctxt, cur));
8128}
8129
8130/**
8131 * xmlXPathNextFollowingSibling:
8132 * @ctxt: the XPath Parser context
8133 * @cur: the current node in the traversal
8134 *
8135 * Traversal function for the "following-sibling" direction
8136 * The following-sibling axis contains the following siblings of the context
8137 * node in document order.
8138 *
8139 * Returns the next element following that axis
8140 */
8141xmlNodePtr
8142xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008143 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008144 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8145 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8146 return(NULL);
8147 if (cur == (xmlNodePtr) ctxt->context->doc)
8148 return(NULL);
8149 if (cur == NULL)
8150 return(ctxt->context->node->next);
8151 return(cur->next);
8152}
8153
8154/**
8155 * xmlXPathNextPrecedingSibling:
8156 * @ctxt: the XPath Parser context
8157 * @cur: the current node in the traversal
8158 *
8159 * Traversal function for the "preceding-sibling" direction
8160 * The preceding-sibling axis contains the preceding siblings of the context
8161 * node in reverse document order; the first preceding sibling is first on the
8162 * axis; the sibling preceding that node is the second on the axis and so on.
8163 *
8164 * Returns the next element following that axis
8165 */
8166xmlNodePtr
8167xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008168 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008169 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8170 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8171 return(NULL);
8172 if (cur == (xmlNodePtr) ctxt->context->doc)
8173 return(NULL);
8174 if (cur == NULL)
8175 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008176 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8177 cur = cur->prev;
8178 if (cur == NULL)
8179 return(ctxt->context->node->prev);
8180 }
Owen Taylor3473f882001-02-23 17:55:21 +00008181 return(cur->prev);
8182}
8183
8184/**
8185 * xmlXPathNextFollowing:
8186 * @ctxt: the XPath Parser context
8187 * @cur: the current node in the traversal
8188 *
8189 * Traversal function for the "following" direction
8190 * The following axis contains all nodes in the same document as the context
8191 * node that are after the context node in document order, excluding any
8192 * descendants and excluding attribute nodes and namespace nodes; the nodes
8193 * are ordered in document order
8194 *
8195 * Returns the next element following that axis
8196 */
8197xmlNodePtr
8198xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008199 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008200 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
8201 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8202 return(cur->children);
8203
8204 if (cur == NULL) {
8205 cur = ctxt->context->node;
8206 if (cur->type == XML_NAMESPACE_DECL)
Daniel Veillard91d19752010-10-15 14:30:52 +02008207 return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008208 if (cur->type == XML_ATTRIBUTE_NODE)
8209 cur = cur->parent;
Daniel Veillard91d19752010-10-15 14:30:52 +02008210 }
Owen Taylor3473f882001-02-23 17:55:21 +00008211 if (cur == NULL) return(NULL) ; /* ERROR */
8212 if (cur->next != NULL) return(cur->next) ;
8213 do {
8214 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00008215 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00008216 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8217 if (cur->next != NULL) return(cur->next);
8218 } while (cur != NULL);
8219 return(cur);
8220}
8221
8222/*
8223 * xmlXPathIsAncestor:
8224 * @ancestor: the ancestor node
8225 * @node: the current node
8226 *
8227 * Check that @ancestor is a @node's ancestor
8228 *
8229 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8230 */
8231static int
8232xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8233 if ((ancestor == NULL) || (node == NULL)) return(0);
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008234 if (node->type == XML_NAMESPACE_DECL)
8235 return(0);
8236 if (ancestor->type == XML_NAMESPACE_DECL)
8237 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00008238 /* nodes need to be in the same document */
8239 if (ancestor->doc != node->doc) return(0);
8240 /* avoid searching if ancestor or node is the root node */
8241 if (ancestor == (xmlNodePtr) node->doc) return(1);
8242 if (node == (xmlNodePtr) ancestor->doc) return(0);
8243 while (node->parent != NULL) {
8244 if (node->parent == ancestor)
8245 return(1);
8246 node = node->parent;
8247 }
8248 return(0);
8249}
8250
8251/**
8252 * xmlXPathNextPreceding:
8253 * @ctxt: the XPath Parser context
8254 * @cur: the current node in the traversal
8255 *
8256 * Traversal function for the "preceding" direction
8257 * the preceding axis contains all nodes in the same document as the context
8258 * node that are before the context node in document order, excluding any
8259 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8260 * ordered in reverse document order
8261 *
8262 * Returns the next element following that axis
8263 */
8264xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00008265xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8266{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008267 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008268 if (cur == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008269 cur = ctxt->context->node;
Daniel Veillardea90b892010-10-22 15:50:50 +02008270 if (cur->type == XML_NAMESPACE_DECL)
8271 return(NULL);
8272 if (cur->type == XML_ATTRIBUTE_NODE)
8273 return(cur->parent);
8274 }
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008275 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
Daniel Veillardf06307e2001-07-03 10:35:50 +00008276 return (NULL);
8277 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8278 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00008279 do {
8280 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008281 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8282 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008283 }
8284
8285 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008286 if (cur == NULL)
8287 return (NULL);
8288 if (cur == ctxt->context->doc->children)
8289 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008290 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00008291 return (cur);
8292}
8293
8294/**
8295 * xmlXPathNextPrecedingInternal:
8296 * @ctxt: the XPath Parser context
8297 * @cur: the current node in the traversal
8298 *
8299 * Traversal function for the "preceding" direction
8300 * the preceding axis contains all nodes in the same document as the context
8301 * node that are before the context node in document order, excluding any
8302 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8303 * ordered in reverse document order
Daniel Veillard45490ae2008-07-29 09:13:19 +00008304 * This is a faster implementation but internal only since it requires a
Daniel Veillardf06307e2001-07-03 10:35:50 +00008305 * state kept in the parser context: ctxt->ancestor.
8306 *
8307 * Returns the next element following that axis
8308 */
8309static xmlNodePtr
8310xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8311 xmlNodePtr cur)
8312{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008313 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008314 if (cur == NULL) {
8315 cur = ctxt->context->node;
8316 if (cur == NULL)
8317 return (NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008318 if (cur->type == XML_NAMESPACE_DECL)
8319 return (NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008320 ctxt->ancestor = cur->parent;
8321 }
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008322 if (cur->type == XML_NAMESPACE_DECL)
8323 return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008324 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8325 cur = cur->prev;
8326 while (cur->prev == NULL) {
8327 cur = cur->parent;
8328 if (cur == NULL)
8329 return (NULL);
8330 if (cur == ctxt->context->doc->children)
8331 return (NULL);
8332 if (cur != ctxt->ancestor)
8333 return (cur);
8334 ctxt->ancestor = cur->parent;
8335 }
8336 cur = cur->prev;
8337 while (cur->last != NULL)
8338 cur = cur->last;
8339 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008340}
8341
8342/**
8343 * xmlXPathNextNamespace:
8344 * @ctxt: the XPath Parser context
8345 * @cur: the current attribute in the traversal
8346 *
8347 * Traversal function for the "namespace" direction
8348 * the namespace axis contains the namespace nodes of the context node;
8349 * the order of nodes on this axis is implementation-defined; the axis will
8350 * be empty unless the context node is an element
8351 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008352 * We keep the XML namespace node at the end of the list.
8353 *
Owen Taylor3473f882001-02-23 17:55:21 +00008354 * Returns the next element following that axis
8355 */
8356xmlNodePtr
8357xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008358 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008359 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00008360 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008361 if (ctxt->context->tmpNsList != NULL)
8362 xmlFree(ctxt->context->tmpNsList);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008363 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00008364 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008365 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00008366 if (ctxt->context->tmpNsList != NULL) {
8367 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8368 ctxt->context->tmpNsNr++;
8369 }
8370 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008371 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008372 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00008373 if (ctxt->context->tmpNsNr > 0) {
8374 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8375 } else {
8376 if (ctxt->context->tmpNsList != NULL)
8377 xmlFree(ctxt->context->tmpNsList);
8378 ctxt->context->tmpNsList = NULL;
8379 return(NULL);
8380 }
Owen Taylor3473f882001-02-23 17:55:21 +00008381}
8382
8383/**
8384 * xmlXPathNextAttribute:
8385 * @ctxt: the XPath Parser context
8386 * @cur: the current attribute in the traversal
8387 *
8388 * Traversal function for the "attribute" direction
8389 * TODO: support DTD inherited default attributes
8390 *
8391 * Returns the next element following that axis
8392 */
8393xmlNodePtr
8394xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008395 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00008396 if (ctxt->context->node == NULL)
8397 return(NULL);
8398 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8399 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008400 if (cur == NULL) {
8401 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8402 return(NULL);
8403 return((xmlNodePtr)ctxt->context->node->properties);
8404 }
8405 return((xmlNodePtr)cur->next);
8406}
8407
8408/************************************************************************
8409 * *
8410 * NodeTest Functions *
8411 * *
8412 ************************************************************************/
8413
Owen Taylor3473f882001-02-23 17:55:21 +00008414#define IS_FUNCTION 200
8415
Owen Taylor3473f882001-02-23 17:55:21 +00008416
8417/************************************************************************
8418 * *
8419 * Implicit tree core function library *
8420 * *
8421 ************************************************************************/
8422
8423/**
8424 * xmlXPathRoot:
8425 * @ctxt: the XPath Parser context
8426 *
8427 * Initialize the context to the root of the document
8428 */
8429void
8430xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008431 if ((ctxt == NULL) || (ctxt->context == NULL))
8432 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008433 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008434 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8435 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008436}
8437
8438/************************************************************************
8439 * *
8440 * The explicit core function library *
8441 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8442 * *
8443 ************************************************************************/
8444
8445
8446/**
8447 * xmlXPathLastFunction:
8448 * @ctxt: the XPath Parser context
8449 * @nargs: the number of arguments
8450 *
8451 * Implement the last() XPath function
8452 * number last()
8453 * The last function returns the number of nodes in the context node list.
8454 */
8455void
8456xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8457 CHECK_ARITY(0);
8458 if (ctxt->context->contextSize >= 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008459 valuePush(ctxt,
8460 xmlXPathCacheNewFloat(ctxt->context,
8461 (double) ctxt->context->contextSize));
Owen Taylor3473f882001-02-23 17:55:21 +00008462#ifdef DEBUG_EXPR
8463 xmlGenericError(xmlGenericErrorContext,
8464 "last() : %d\n", ctxt->context->contextSize);
8465#endif
8466 } else {
8467 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8468 }
8469}
8470
8471/**
8472 * xmlXPathPositionFunction:
8473 * @ctxt: the XPath Parser context
8474 * @nargs: the number of arguments
8475 *
8476 * Implement the position() XPath function
8477 * number position()
8478 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008479 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00008480 * will be equal to last().
8481 */
8482void
8483xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8484 CHECK_ARITY(0);
8485 if (ctxt->context->proximityPosition >= 0) {
8486 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008487 xmlXPathCacheNewFloat(ctxt->context,
8488 (double) ctxt->context->proximityPosition));
Owen Taylor3473f882001-02-23 17:55:21 +00008489#ifdef DEBUG_EXPR
8490 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8491 ctxt->context->proximityPosition);
8492#endif
8493 } else {
8494 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8495 }
8496}
8497
8498/**
8499 * xmlXPathCountFunction:
8500 * @ctxt: the XPath Parser context
8501 * @nargs: the number of arguments
8502 *
8503 * Implement the count() XPath function
8504 * number count(node-set)
8505 */
8506void
8507xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8508 xmlXPathObjectPtr cur;
8509
8510 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008511 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008512 ((ctxt->value->type != XPATH_NODESET) &&
8513 (ctxt->value->type != XPATH_XSLT_TREE)))
8514 XP_ERROR(XPATH_INVALID_TYPE);
8515 cur = valuePop(ctxt);
8516
Daniel Veillard911f49a2001-04-07 15:39:35 +00008517 if ((cur == NULL) || (cur->nodesetval == NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008518 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00008519 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008520 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8521 (double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00008522 } else {
8523 if ((cur->nodesetval->nodeNr != 1) ||
8524 (cur->nodesetval->nodeTab == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008525 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00008526 } else {
8527 xmlNodePtr tmp;
8528 int i = 0;
8529
8530 tmp = cur->nodesetval->nodeTab[0];
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008531 if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) {
Daniel Veillardfe703322001-08-14 12:18:09 +00008532 tmp = tmp->children;
8533 while (tmp != NULL) {
8534 tmp = tmp->next;
8535 i++;
8536 }
8537 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008538 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
Daniel Veillardfe703322001-08-14 12:18:09 +00008539 }
8540 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008541 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008542}
8543
8544/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008545 * xmlXPathGetElementsByIds:
8546 * @doc: the document
8547 * @ids: a whitespace separated list of IDs
8548 *
8549 * Selects elements by their unique ID.
8550 *
8551 * Returns a node-set of selected elements.
8552 */
8553static xmlNodeSetPtr
8554xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8555 xmlNodeSetPtr ret;
8556 const xmlChar *cur = ids;
8557 xmlChar *ID;
8558 xmlAttrPtr attr;
8559 xmlNodePtr elem = NULL;
8560
Daniel Veillard7a985a12003-07-06 17:57:42 +00008561 if (ids == NULL) return(NULL);
8562
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008563 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00008564 if (ret == NULL)
8565 return(ret);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008566
William M. Brack76e95df2003-10-18 16:20:14 +00008567 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008568 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008569 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00008570 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008571
8572 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00008573 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00008574 /*
8575 * We used to check the fact that the value passed
8576 * was an NCName, but this generated much troubles for
8577 * me and Aleksey Sanin, people blatantly violated that
8578 * constaint, like Visa3D spec.
8579 * if (xmlValidateNCName(ID, 1) == 0)
8580 */
8581 attr = xmlGetID(doc, ID);
8582 if (attr != NULL) {
8583 if (attr->type == XML_ATTRIBUTE_NODE)
8584 elem = attr->parent;
8585 else if (attr->type == XML_ELEMENT_NODE)
8586 elem = (xmlNodePtr) attr;
8587 else
8588 elem = NULL;
8589 if (elem != NULL)
8590 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00008591 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008592 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00008593 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008594
William M. Brack76e95df2003-10-18 16:20:14 +00008595 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008596 ids = cur;
8597 }
8598 return(ret);
8599}
8600
8601/**
Owen Taylor3473f882001-02-23 17:55:21 +00008602 * xmlXPathIdFunction:
8603 * @ctxt: the XPath Parser context
8604 * @nargs: the number of arguments
8605 *
8606 * Implement the id() XPath function
8607 * node-set id(object)
8608 * The id function selects elements by their unique ID
8609 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8610 * then the result is the union of the result of applying id to the
8611 * string value of each of the nodes in the argument node-set. When the
8612 * argument to id is of any other type, the argument is converted to a
8613 * string as if by a call to the string function; the string is split
8614 * into a whitespace-separated list of tokens (whitespace is any sequence
8615 * of characters matching the production S); the result is a node-set
8616 * containing the elements in the same document as the context node that
8617 * have a unique ID equal to any of the tokens in the list.
8618 */
8619void
8620xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008621 xmlChar *tokens;
8622 xmlNodeSetPtr ret;
8623 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00008624
8625 CHECK_ARITY(1);
8626 obj = valuePop(ctxt);
8627 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00008628 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008629 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00008630 int i;
8631
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008632 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00008633 /*
8634 * FIXME -- in an out-of-memory condition this will behave badly.
8635 * The solution is not clear -- we already popped an item from
8636 * ctxt, so the object is in a corrupt state.
8637 */
Owen Taylor3473f882001-02-23 17:55:21 +00008638
Daniel Veillard911f49a2001-04-07 15:39:35 +00008639 if (obj->nodesetval != NULL) {
8640 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008641 tokens =
8642 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8643 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8644 ret = xmlXPathNodeSetMerge(ret, ns);
8645 xmlXPathFreeNodeSet(ns);
8646 if (tokens != NULL)
8647 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00008648 }
Owen Taylor3473f882001-02-23 17:55:21 +00008649 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008650 xmlXPathReleaseObject(ctxt->context, obj);
8651 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00008652 return;
8653 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008654 obj = xmlXPathCacheConvertString(ctxt->context, obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008655 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008656 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008657 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00008658 return;
8659}
8660
8661/**
8662 * xmlXPathLocalNameFunction:
8663 * @ctxt: the XPath Parser context
8664 * @nargs: the number of arguments
8665 *
8666 * Implement the local-name() XPath function
8667 * string local-name(node-set?)
8668 * The local-name function returns a string containing the local part
8669 * of the name of the node in the argument node-set that is first in
8670 * document order. If the node-set is empty or the first node has no
8671 * name, an empty string is returned. If the argument is omitted it
8672 * defaults to the context node.
8673 */
8674void
8675xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8676 xmlXPathObjectPtr cur;
8677
Daniel Veillarda82b1822004-11-08 16:24:57 +00008678 if (ctxt == NULL) return;
8679
Owen Taylor3473f882001-02-23 17:55:21 +00008680 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008681 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8682 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008683 nargs = 1;
8684 }
8685
8686 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008687 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008688 ((ctxt->value->type != XPATH_NODESET) &&
8689 (ctxt->value->type != XPATH_XSLT_TREE)))
8690 XP_ERROR(XPATH_INVALID_TYPE);
8691 cur = valuePop(ctxt);
8692
Daniel Veillard911f49a2001-04-07 15:39:35 +00008693 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008694 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008695 } else {
8696 int i = 0; /* Should be first in document order !!!!! */
8697 switch (cur->nodesetval->nodeTab[i]->type) {
8698 case XML_ELEMENT_NODE:
8699 case XML_ATTRIBUTE_NODE:
8700 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008701 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008702 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008703 else
8704 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008705 xmlXPathCacheNewString(ctxt->context,
8706 cur->nodesetval->nodeTab[i]->name));
Owen Taylor3473f882001-02-23 17:55:21 +00008707 break;
8708 case XML_NAMESPACE_DECL:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008709 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008710 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8711 break;
8712 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008713 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008714 }
8715 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008716 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008717}
8718
8719/**
8720 * xmlXPathNamespaceURIFunction:
8721 * @ctxt: the XPath Parser context
8722 * @nargs: the number of arguments
8723 *
8724 * Implement the namespace-uri() XPath function
8725 * string namespace-uri(node-set?)
8726 * The namespace-uri function returns a string containing the
8727 * namespace URI of the expanded name of the node in the argument
8728 * node-set that is first in document order. If the node-set is empty,
8729 * the first node has no name, or the expanded name has no namespace
8730 * URI, an empty string is returned. If the argument is omitted it
8731 * defaults to the context node.
8732 */
8733void
8734xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8735 xmlXPathObjectPtr cur;
8736
Daniel Veillarda82b1822004-11-08 16:24:57 +00008737 if (ctxt == NULL) return;
8738
Owen Taylor3473f882001-02-23 17:55:21 +00008739 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008740 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8741 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008742 nargs = 1;
8743 }
8744 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008745 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008746 ((ctxt->value->type != XPATH_NODESET) &&
8747 (ctxt->value->type != XPATH_XSLT_TREE)))
8748 XP_ERROR(XPATH_INVALID_TYPE);
8749 cur = valuePop(ctxt);
8750
Daniel Veillard911f49a2001-04-07 15:39:35 +00008751 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008752 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008753 } else {
8754 int i = 0; /* Should be first in document order !!!!! */
8755 switch (cur->nodesetval->nodeTab[i]->type) {
8756 case XML_ELEMENT_NODE:
8757 case XML_ATTRIBUTE_NODE:
8758 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008759 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008760 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008761 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008762 cur->nodesetval->nodeTab[i]->ns->href));
8763 break;
8764 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008765 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008766 }
8767 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008768 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008769}
8770
8771/**
8772 * xmlXPathNameFunction:
8773 * @ctxt: the XPath Parser context
8774 * @nargs: the number of arguments
8775 *
8776 * Implement the name() XPath function
8777 * string name(node-set?)
8778 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008779 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00008780 * order. The QName must represent the name with respect to the namespace
8781 * declarations in effect on the node whose name is being represented.
8782 * Typically, this will be the form in which the name occurred in the XML
8783 * source. This need not be the case if there are namespace declarations
8784 * in effect on the node that associate multiple prefixes with the same
8785 * namespace. However, an implementation may include information about
8786 * the original prefix in its representation of nodes; in this case, an
8787 * implementation can ensure that the returned string is always the same
8788 * as the QName used in the XML source. If the argument it omitted it
8789 * defaults to the context node.
8790 * Libxml keep the original prefix so the "real qualified name" used is
8791 * returned.
8792 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008793static void
Daniel Veillard04383752001-07-08 14:27:15 +00008794xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8795{
Owen Taylor3473f882001-02-23 17:55:21 +00008796 xmlXPathObjectPtr cur;
8797
8798 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008799 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8800 ctxt->context->node));
Daniel Veillard04383752001-07-08 14:27:15 +00008801 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008802 }
8803
8804 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00008805 if ((ctxt->value == NULL) ||
8806 ((ctxt->value->type != XPATH_NODESET) &&
8807 (ctxt->value->type != XPATH_XSLT_TREE)))
8808 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00008809 cur = valuePop(ctxt);
8810
Daniel Veillard911f49a2001-04-07 15:39:35 +00008811 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008812 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008813 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00008814 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00008815
Daniel Veillard04383752001-07-08 14:27:15 +00008816 switch (cur->nodesetval->nodeTab[i]->type) {
8817 case XML_ELEMENT_NODE:
8818 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008819 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008820 valuePush(ctxt,
8821 xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008822 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8823 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008824 valuePush(ctxt,
8825 xmlXPathCacheNewString(ctxt->context,
8826 cur->nodesetval->nodeTab[i]->name));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008827 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00008828 xmlChar *fullname;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008829
Daniel Veillardc00cda82003-04-07 10:22:39 +00008830 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8831 cur->nodesetval->nodeTab[i]->ns->prefix,
8832 NULL, 0);
8833 if (fullname == cur->nodesetval->nodeTab[i]->name)
8834 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8835 if (fullname == NULL) {
8836 XP_ERROR(XPATH_MEMORY_ERROR);
8837 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008838 valuePush(ctxt, xmlXPathCacheWrapString(
8839 ctxt->context, fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00008840 }
8841 break;
8842 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008843 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8844 cur->nodesetval->nodeTab[i]));
Daniel Veillard04383752001-07-08 14:27:15 +00008845 xmlXPathLocalNameFunction(ctxt, 1);
8846 }
Owen Taylor3473f882001-02-23 17:55:21 +00008847 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008848 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008849}
8850
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008851
8852/**
Owen Taylor3473f882001-02-23 17:55:21 +00008853 * xmlXPathStringFunction:
8854 * @ctxt: the XPath Parser context
8855 * @nargs: the number of arguments
8856 *
8857 * Implement the string() XPath function
8858 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00008859 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00008860 * - A node-set is converted to a string by returning the value of
8861 * the node in the node-set that is first in document order.
8862 * If the node-set is empty, an empty string is returned.
8863 * - A number is converted to a string as follows
Daniel Veillard45490ae2008-07-29 09:13:19 +00008864 * + NaN is converted to the string NaN
8865 * + positive zero is converted to the string 0
8866 * + negative zero is converted to the string 0
8867 * + positive infinity is converted to the string Infinity
8868 * + negative infinity is converted to the string -Infinity
Owen Taylor3473f882001-02-23 17:55:21 +00008869 * + if the number is an integer, the number is represented in
8870 * decimal form as a Number with no decimal point and no leading
8871 * zeros, preceded by a minus sign (-) if the number is negative
8872 * + otherwise, the number is represented in decimal form as a
8873 * Number including a decimal point with at least one digit
8874 * before the decimal point and at least one digit after the
8875 * decimal point, preceded by a minus sign (-) if the number
8876 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008877 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00008878 * before the decimal point; beyond the one required digit
8879 * after the decimal point there must be as many, but only as
8880 * many, more digits as are needed to uniquely distinguish the
8881 * number from all other IEEE 754 numeric values.
8882 * - The boolean false value is converted to the string false.
8883 * The boolean true value is converted to the string true.
8884 *
8885 * If the argument is omitted, it defaults to a node-set with the
8886 * context node as its only member.
8887 */
8888void
8889xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8890 xmlXPathObjectPtr cur;
8891
Daniel Veillarda82b1822004-11-08 16:24:57 +00008892 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008893 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008894 valuePush(ctxt,
8895 xmlXPathCacheWrapString(ctxt->context,
8896 xmlXPathCastNodeToString(ctxt->context->node)));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008897 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008898 }
8899
8900 CHECK_ARITY(1);
8901 cur = valuePop(ctxt);
8902 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008903 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00008904}
8905
8906/**
8907 * xmlXPathStringLengthFunction:
8908 * @ctxt: the XPath Parser context
8909 * @nargs: the number of arguments
8910 *
8911 * Implement the string-length() XPath function
8912 * number string-length(string?)
8913 * The string-length returns the number of characters in the string
8914 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8915 * the context node converted to a string, in other words the value
8916 * of the context node.
8917 */
8918void
8919xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8920 xmlXPathObjectPtr cur;
8921
8922 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008923 if ((ctxt == NULL) || (ctxt->context == NULL))
8924 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008925 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008926 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008927 } else {
8928 xmlChar *content;
8929
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008930 content = xmlXPathCastNodeToString(ctxt->context->node);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008931 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8932 xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00008933 xmlFree(content);
8934 }
8935 return;
8936 }
8937 CHECK_ARITY(1);
8938 CAST_TO_STRING;
8939 CHECK_TYPE(XPATH_STRING);
8940 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008941 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
Daniel Veillard45490ae2008-07-29 09:13:19 +00008942 xmlUTF8Strlen(cur->stringval)));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008943 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008944}
8945
8946/**
8947 * xmlXPathConcatFunction:
8948 * @ctxt: the XPath Parser context
8949 * @nargs: the number of arguments
8950 *
8951 * Implement the concat() XPath function
8952 * string concat(string, string, string*)
8953 * The concat function returns the concatenation of its arguments.
8954 */
8955void
8956xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8957 xmlXPathObjectPtr cur, newobj;
8958 xmlChar *tmp;
8959
Daniel Veillarda82b1822004-11-08 16:24:57 +00008960 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008961 if (nargs < 2) {
8962 CHECK_ARITY(2);
8963 }
8964
8965 CAST_TO_STRING;
8966 cur = valuePop(ctxt);
8967 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008968 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008969 return;
8970 }
8971 nargs--;
8972
8973 while (nargs > 0) {
8974 CAST_TO_STRING;
8975 newobj = valuePop(ctxt);
8976 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008977 xmlXPathReleaseObject(ctxt->context, newobj);
8978 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008979 XP_ERROR(XPATH_INVALID_TYPE);
8980 }
8981 tmp = xmlStrcat(newobj->stringval, cur->stringval);
8982 newobj->stringval = cur->stringval;
8983 cur->stringval = tmp;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008984 xmlXPathReleaseObject(ctxt->context, newobj);
Owen Taylor3473f882001-02-23 17:55:21 +00008985 nargs--;
8986 }
8987 valuePush(ctxt, cur);
8988}
8989
8990/**
8991 * xmlXPathContainsFunction:
8992 * @ctxt: the XPath Parser context
8993 * @nargs: the number of arguments
8994 *
8995 * Implement the contains() XPath function
8996 * boolean contains(string, string)
8997 * The contains function returns true if the first argument string
8998 * contains the second argument string, and otherwise returns false.
8999 */
9000void
9001xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9002 xmlXPathObjectPtr hay, needle;
9003
9004 CHECK_ARITY(2);
9005 CAST_TO_STRING;
9006 CHECK_TYPE(XPATH_STRING);
9007 needle = valuePop(ctxt);
9008 CAST_TO_STRING;
9009 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009010
Owen Taylor3473f882001-02-23 17:55:21 +00009011 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009012 xmlXPathReleaseObject(ctxt->context, hay);
9013 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009014 XP_ERROR(XPATH_INVALID_TYPE);
9015 }
9016 if (xmlStrstr(hay->stringval, needle->stringval))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009017 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009018 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009019 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9020 xmlXPathReleaseObject(ctxt->context, hay);
9021 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009022}
9023
9024/**
9025 * xmlXPathStartsWithFunction:
9026 * @ctxt: the XPath Parser context
9027 * @nargs: the number of arguments
9028 *
9029 * Implement the starts-with() XPath function
9030 * boolean starts-with(string, string)
9031 * The starts-with function returns true if the first argument string
9032 * starts with the second argument string, and otherwise returns false.
9033 */
9034void
9035xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9036 xmlXPathObjectPtr hay, needle;
9037 int n;
9038
9039 CHECK_ARITY(2);
9040 CAST_TO_STRING;
9041 CHECK_TYPE(XPATH_STRING);
9042 needle = valuePop(ctxt);
9043 CAST_TO_STRING;
9044 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009045
Owen Taylor3473f882001-02-23 17:55:21 +00009046 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009047 xmlXPathReleaseObject(ctxt->context, hay);
9048 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009049 XP_ERROR(XPATH_INVALID_TYPE);
9050 }
9051 n = xmlStrlen(needle->stringval);
9052 if (xmlStrncmp(hay->stringval, needle->stringval, n))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009053 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009054 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009055 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9056 xmlXPathReleaseObject(ctxt->context, hay);
9057 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009058}
9059
9060/**
9061 * xmlXPathSubstringFunction:
9062 * @ctxt: the XPath Parser context
9063 * @nargs: the number of arguments
9064 *
9065 * Implement the substring() XPath function
9066 * string substring(string, number, number?)
9067 * The substring function returns the substring of the first argument
9068 * starting at the position specified in the second argument with
9069 * length specified in the third argument. For example,
9070 * substring("12345",2,3) returns "234". If the third argument is not
9071 * specified, it returns the substring starting at the position specified
9072 * in the second argument and continuing to the end of the string. For
9073 * example, substring("12345",2) returns "2345". More precisely, each
9074 * character in the string (see [3.6 Strings]) is considered to have a
9075 * numeric position: the position of the first character is 1, the position
9076 * of the second character is 2 and so on. The returned substring contains
9077 * those characters for which the position of the character is greater than
9078 * or equal to the second argument and, if the third argument is specified,
9079 * less than the sum of the second and third arguments; the comparisons
9080 * and addition used for the above follow the standard IEEE 754 rules. Thus:
Daniel Veillard45490ae2008-07-29 09:13:19 +00009081 * - substring("12345", 1.5, 2.6) returns "234"
9082 * - substring("12345", 0, 3) returns "12"
9083 * - substring("12345", 0 div 0, 3) returns ""
9084 * - substring("12345", 1, 0 div 0) returns ""
9085 * - substring("12345", -42, 1 div 0) returns "12345"
9086 * - substring("12345", -1 div 0, 1 div 0) returns ""
Owen Taylor3473f882001-02-23 17:55:21 +00009087 */
9088void
9089xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9090 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009091 double le=0, in;
9092 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00009093 xmlChar *ret;
9094
Owen Taylor3473f882001-02-23 17:55:21 +00009095 if (nargs < 2) {
9096 CHECK_ARITY(2);
9097 }
9098 if (nargs > 3) {
9099 CHECK_ARITY(3);
9100 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009101 /*
9102 * take care of possible last (position) argument
9103 */
Owen Taylor3473f882001-02-23 17:55:21 +00009104 if (nargs == 3) {
9105 CAST_TO_NUMBER;
9106 CHECK_TYPE(XPATH_NUMBER);
9107 len = valuePop(ctxt);
9108 le = len->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009109 xmlXPathReleaseObject(ctxt->context, len);
Owen Taylor3473f882001-02-23 17:55:21 +00009110 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009111
Owen Taylor3473f882001-02-23 17:55:21 +00009112 CAST_TO_NUMBER;
9113 CHECK_TYPE(XPATH_NUMBER);
9114 start = valuePop(ctxt);
9115 in = start->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009116 xmlXPathReleaseObject(ctxt->context, start);
Owen Taylor3473f882001-02-23 17:55:21 +00009117 CAST_TO_STRING;
9118 CHECK_TYPE(XPATH_STRING);
9119 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00009120 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00009121
Daniel Veillard97ac1312001-05-30 19:14:17 +00009122 /*
9123 * If last pos not present, calculate last position
9124 */
Daniel Veillard9e412302002-06-10 15:59:44 +00009125 if (nargs != 3) {
9126 le = (double)m;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009127 if (in < 1.0)
Daniel Veillard9e412302002-06-10 15:59:44 +00009128 in = 1.0;
9129 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009130
Daniel Veillard45490ae2008-07-29 09:13:19 +00009131 /* Need to check for the special cases where either
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009132 * the index is NaN, the length is NaN, or both
9133 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00009134 */
Daniel Veillard48b3eb22009-03-25 09:51:19 +00009135 if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009136 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00009137 * To meet the requirements of the spec, the arguments
Daniel Veillard45490ae2008-07-29 09:13:19 +00009138 * must be converted to integer format before
Daniel Veillard9e412302002-06-10 15:59:44 +00009139 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009140 *
Daniel Veillard9e412302002-06-10 15:59:44 +00009141 * First we go to integer form, rounding up
9142 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009143 */
9144 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00009145 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00009146
Daniel Veillard9e412302002-06-10 15:59:44 +00009147 if (xmlXPathIsInf(le) == 1) {
9148 l = m;
9149 if (i < 1)
9150 i = 1;
9151 }
9152 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9153 l = 0;
9154 else {
9155 l = (int) le;
9156 if (((double)l)+0.5 <= le) l++;
9157 }
9158
9159 /* Now we normalize inidices */
9160 i -= 1;
9161 l += i;
9162 if (i < 0)
9163 i = 0;
9164 if (l > m)
9165 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00009166
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009167 /* number of chars to copy */
9168 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00009169
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009170 ret = xmlUTF8Strsub(str->stringval, i, l);
9171 }
9172 else {
9173 ret = NULL;
9174 }
Owen Taylor3473f882001-02-23 17:55:21 +00009175 if (ret == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009176 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00009177 else {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009178 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009179 xmlFree(ret);
9180 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009181 xmlXPathReleaseObject(ctxt->context, str);
Owen Taylor3473f882001-02-23 17:55:21 +00009182}
9183
9184/**
9185 * xmlXPathSubstringBeforeFunction:
9186 * @ctxt: the XPath Parser context
9187 * @nargs: the number of arguments
9188 *
9189 * Implement the substring-before() XPath function
9190 * string substring-before(string, string)
9191 * The substring-before function returns the substring of the first
9192 * argument string that precedes the first occurrence of the second
9193 * argument string in the first argument string, or the empty string
9194 * if the first argument string does not contain the second argument
9195 * string. For example, substring-before("1999/04/01","/") returns 1999.
9196 */
9197void
9198xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9199 xmlXPathObjectPtr str;
9200 xmlXPathObjectPtr find;
Daniel Veillardade10f22012-07-12 09:43:27 +08009201 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009202 const xmlChar *point;
9203 int offset;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009204
Owen Taylor3473f882001-02-23 17:55:21 +00009205 CHECK_ARITY(2);
9206 CAST_TO_STRING;
9207 find = valuePop(ctxt);
9208 CAST_TO_STRING;
9209 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009210
Daniel Veillardade10f22012-07-12 09:43:27 +08009211 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009212 if (target) {
9213 point = xmlStrstr(str->stringval, find->stringval);
9214 if (point) {
9215 offset = (int)(point - str->stringval);
Daniel Veillardade10f22012-07-12 09:43:27 +08009216 xmlBufAdd(target, str->stringval, offset);
Owen Taylor3473f882001-02-23 17:55:21 +00009217 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009218 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009219 xmlBufContent(target)));
9220 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009221 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009222 xmlXPathReleaseObject(ctxt->context, str);
9223 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009224}
9225
9226/**
9227 * xmlXPathSubstringAfterFunction:
9228 * @ctxt: the XPath Parser context
9229 * @nargs: the number of arguments
9230 *
9231 * Implement the substring-after() XPath function
9232 * string substring-after(string, string)
9233 * The substring-after function returns the substring of the first
9234 * argument string that follows the first occurrence of the second
9235 * argument string in the first argument string, or the empty stringi
9236 * if the first argument string does not contain the second argument
9237 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9238 * and substring-after("1999/04/01","19") returns 99/04/01.
9239 */
9240void
9241xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9242 xmlXPathObjectPtr str;
9243 xmlXPathObjectPtr find;
Daniel Veillardade10f22012-07-12 09:43:27 +08009244 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009245 const xmlChar *point;
9246 int offset;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009247
Owen Taylor3473f882001-02-23 17:55:21 +00009248 CHECK_ARITY(2);
9249 CAST_TO_STRING;
9250 find = valuePop(ctxt);
9251 CAST_TO_STRING;
9252 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009253
Daniel Veillardade10f22012-07-12 09:43:27 +08009254 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009255 if (target) {
9256 point = xmlStrstr(str->stringval, find->stringval);
9257 if (point) {
9258 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
Daniel Veillardade10f22012-07-12 09:43:27 +08009259 xmlBufAdd(target, &str->stringval[offset],
Owen Taylor3473f882001-02-23 17:55:21 +00009260 xmlStrlen(str->stringval) - offset);
9261 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009262 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009263 xmlBufContent(target)));
9264 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009265 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009266 xmlXPathReleaseObject(ctxt->context, str);
9267 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009268}
9269
9270/**
9271 * xmlXPathNormalizeFunction:
9272 * @ctxt: the XPath Parser context
9273 * @nargs: the number of arguments
9274 *
9275 * Implement the normalize-space() XPath function
9276 * string normalize-space(string?)
9277 * The normalize-space function returns the argument string with white
9278 * space normalized by stripping leading and trailing whitespace
9279 * and replacing sequences of whitespace characters by a single
9280 * space. Whitespace characters are the same allowed by the S production
9281 * in XML. If the argument is omitted, it defaults to the context
9282 * node converted to a string, in other words the value of the context node.
9283 */
9284void
9285xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9286 xmlXPathObjectPtr obj = NULL;
9287 xmlChar *source = NULL;
Daniel Veillardade10f22012-07-12 09:43:27 +08009288 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009289 xmlChar blank;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009290
Daniel Veillarda82b1822004-11-08 16:24:57 +00009291 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009292 if (nargs == 0) {
9293 /* Use current context node */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009294 valuePush(ctxt,
9295 xmlXPathCacheWrapString(ctxt->context,
9296 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00009297 nargs = 1;
9298 }
9299
9300 CHECK_ARITY(1);
9301 CAST_TO_STRING;
9302 CHECK_TYPE(XPATH_STRING);
9303 obj = valuePop(ctxt);
9304 source = obj->stringval;
9305
Daniel Veillardade10f22012-07-12 09:43:27 +08009306 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009307 if (target && source) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00009308
Owen Taylor3473f882001-02-23 17:55:21 +00009309 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00009310 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00009311 source++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009312
Owen Taylor3473f882001-02-23 17:55:21 +00009313 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9314 blank = 0;
9315 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00009316 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009317 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00009318 } else {
9319 if (blank) {
Daniel Veillardade10f22012-07-12 09:43:27 +08009320 xmlBufAdd(target, &blank, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00009321 blank = 0;
9322 }
Daniel Veillardade10f22012-07-12 09:43:27 +08009323 xmlBufAdd(target, source, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00009324 }
9325 source++;
9326 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009327 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009328 xmlBufContent(target)));
9329 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009330 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009331 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00009332}
9333
9334/**
9335 * xmlXPathTranslateFunction:
9336 * @ctxt: the XPath Parser context
9337 * @nargs: the number of arguments
9338 *
9339 * Implement the translate() XPath function
9340 * string translate(string, string, string)
9341 * The translate function returns the first argument string with
9342 * occurrences of characters in the second argument string replaced
9343 * by the character at the corresponding position in the third argument
9344 * string. For example, translate("bar","abc","ABC") returns the string
9345 * BAr. If there is a character in the second argument string with no
9346 * character at a corresponding position in the third argument string
9347 * (because the second argument string is longer than the third argument
9348 * string), then occurrences of that character in the first argument
9349 * string are removed. For example, translate("--aaa--","abc-","ABC")
9350 * returns "AAA". If a character occurs more than once in second
9351 * argument string, then the first occurrence determines the replacement
9352 * character. If the third argument string is longer than the second
9353 * argument string, then excess characters are ignored.
9354 */
9355void
9356xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00009357 xmlXPathObjectPtr str;
9358 xmlXPathObjectPtr from;
9359 xmlXPathObjectPtr to;
Daniel Veillardade10f22012-07-12 09:43:27 +08009360 xmlBufPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009361 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009362 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00009363 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009364 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00009365
Daniel Veillarde043ee12001-04-16 14:08:07 +00009366 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00009367
Daniel Veillarde043ee12001-04-16 14:08:07 +00009368 CAST_TO_STRING;
9369 to = valuePop(ctxt);
9370 CAST_TO_STRING;
9371 from = valuePop(ctxt);
9372 CAST_TO_STRING;
9373 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009374
Daniel Veillardade10f22012-07-12 09:43:27 +08009375 target = xmlBufCreate();
Daniel Veillarde043ee12001-04-16 14:08:07 +00009376 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009377 max = xmlUTF8Strlen(to->stringval);
9378 for (cptr = str->stringval; (ch=*cptr); ) {
9379 offset = xmlUTF8Strloc(from->stringval, cptr);
9380 if (offset >= 0) {
9381 if (offset < max) {
9382 point = xmlUTF8Strpos(to->stringval, offset);
9383 if (point)
Daniel Veillardade10f22012-07-12 09:43:27 +08009384 xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
Daniel Veillard97ac1312001-05-30 19:14:17 +00009385 }
9386 } else
Daniel Veillardade10f22012-07-12 09:43:27 +08009387 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
Daniel Veillard97ac1312001-05-30 19:14:17 +00009388
9389 /* Step to next character in input */
9390 cptr++;
9391 if ( ch & 0x80 ) {
9392 /* if not simple ascii, verify proper format */
9393 if ( (ch & 0xc0) != 0xc0 ) {
9394 xmlGenericError(xmlGenericErrorContext,
9395 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08009396 /* not asserting an XPath error is probably better */
Daniel Veillard97ac1312001-05-30 19:14:17 +00009397 break;
9398 }
9399 /* then skip over remaining bytes for this char */
9400 while ( (ch <<= 1) & 0x80 )
9401 if ( (*cptr++ & 0xc0) != 0x80 ) {
9402 xmlGenericError(xmlGenericErrorContext,
9403 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08009404 /* not asserting an XPath error is probably better */
Daniel Veillard97ac1312001-05-30 19:14:17 +00009405 break;
9406 }
9407 if (ch & 0x80) /* must have had error encountered */
9408 break;
9409 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00009410 }
Owen Taylor3473f882001-02-23 17:55:21 +00009411 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009412 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009413 xmlBufContent(target)));
9414 xmlBufFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009415 xmlXPathReleaseObject(ctxt->context, str);
9416 xmlXPathReleaseObject(ctxt->context, from);
9417 xmlXPathReleaseObject(ctxt->context, to);
Owen Taylor3473f882001-02-23 17:55:21 +00009418}
9419
9420/**
9421 * xmlXPathBooleanFunction:
9422 * @ctxt: the XPath Parser context
9423 * @nargs: the number of arguments
9424 *
9425 * Implement the boolean() XPath function
9426 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00009427 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00009428 * - a number is true if and only if it is neither positive or
9429 * negative zero nor NaN
9430 * - a node-set is true if and only if it is non-empty
9431 * - a string is true if and only if its length is non-zero
9432 */
9433void
9434xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9435 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00009436
9437 CHECK_ARITY(1);
9438 cur = valuePop(ctxt);
9439 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009440 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009441 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009442}
9443
9444/**
9445 * xmlXPathNotFunction:
9446 * @ctxt: the XPath Parser context
9447 * @nargs: the number of arguments
9448 *
9449 * Implement the not() XPath function
9450 * boolean not(boolean)
9451 * The not function returns true if its argument is false,
9452 * and false otherwise.
9453 */
9454void
9455xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9456 CHECK_ARITY(1);
9457 CAST_TO_BOOLEAN;
9458 CHECK_TYPE(XPATH_BOOLEAN);
9459 ctxt->value->boolval = ! ctxt->value->boolval;
9460}
9461
9462/**
9463 * xmlXPathTrueFunction:
9464 * @ctxt: the XPath Parser context
9465 * @nargs: the number of arguments
9466 *
9467 * Implement the true() XPath function
9468 * boolean true()
9469 */
9470void
9471xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9472 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009473 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009474}
9475
9476/**
9477 * xmlXPathFalseFunction:
9478 * @ctxt: the XPath Parser context
9479 * @nargs: the number of arguments
9480 *
9481 * Implement the false() XPath function
9482 * boolean false()
9483 */
9484void
9485xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9486 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009487 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009488}
9489
9490/**
9491 * xmlXPathLangFunction:
9492 * @ctxt: the XPath Parser context
9493 * @nargs: the number of arguments
9494 *
9495 * Implement the lang() XPath function
9496 * boolean lang(string)
9497 * The lang function returns true or false depending on whether the
9498 * language of the context node as specified by xml:lang attributes
9499 * is the same as or is a sublanguage of the language specified by
9500 * the argument string. The language of the context node is determined
9501 * by the value of the xml:lang attribute on the context node, or, if
9502 * the context node has no xml:lang attribute, by the value of the
9503 * xml:lang attribute on the nearest ancestor of the context node that
9504 * has an xml:lang attribute. If there is no such attribute, then lang
9505 * returns false. If there is such an attribute, then lang returns
9506 * true if the attribute value is equal to the argument ignoring case,
9507 * or if there is some suffix starting with - such that the attribute
9508 * value is equal to the argument ignoring that suffix of the attribute
9509 * value and ignoring case.
9510 */
9511void
9512xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009513 xmlXPathObjectPtr val = NULL;
9514 const xmlChar *theLang = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009515 const xmlChar *lang;
9516 int ret = 0;
9517 int i;
9518
9519 CHECK_ARITY(1);
9520 CAST_TO_STRING;
9521 CHECK_TYPE(XPATH_STRING);
9522 val = valuePop(ctxt);
9523 lang = val->stringval;
9524 theLang = xmlNodeGetLang(ctxt->context->node);
9525 if ((theLang != NULL) && (lang != NULL)) {
9526 for (i = 0;lang[i] != 0;i++)
9527 if (toupper(lang[i]) != toupper(theLang[i]))
9528 goto not_equal;
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009529 if ((theLang[i] == 0) || (theLang[i] == '-'))
9530 ret = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009531 }
9532not_equal:
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009533 if (theLang != NULL)
9534 xmlFree((void *)theLang);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009535
9536 xmlXPathReleaseObject(ctxt->context, val);
9537 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009538}
9539
9540/**
9541 * xmlXPathNumberFunction:
9542 * @ctxt: the XPath Parser context
9543 * @nargs: the number of arguments
9544 *
9545 * Implement the number() XPath function
9546 * number number(object?)
9547 */
9548void
9549xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9550 xmlXPathObjectPtr cur;
9551 double res;
9552
Daniel Veillarda82b1822004-11-08 16:24:57 +00009553 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009554 if (nargs == 0) {
9555 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009556 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
Owen Taylor3473f882001-02-23 17:55:21 +00009557 } else {
9558 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9559
9560 res = xmlXPathStringEvalNumber(content);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009561 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
Owen Taylor3473f882001-02-23 17:55:21 +00009562 xmlFree(content);
9563 }
9564 return;
9565 }
9566
9567 CHECK_ARITY(1);
9568 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009569 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00009570}
9571
9572/**
9573 * xmlXPathSumFunction:
9574 * @ctxt: the XPath Parser context
9575 * @nargs: the number of arguments
9576 *
9577 * Implement the sum() XPath function
9578 * number sum(node-set)
9579 * The sum function returns the sum of the values of the nodes in
9580 * the argument node-set.
9581 */
9582void
9583xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9584 xmlXPathObjectPtr cur;
9585 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009586 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00009587
9588 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009589 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009590 ((ctxt->value->type != XPATH_NODESET) &&
9591 (ctxt->value->type != XPATH_XSLT_TREE)))
9592 XP_ERROR(XPATH_INVALID_TYPE);
9593 cur = valuePop(ctxt);
9594
William M. Brack08171912003-12-29 02:52:11 +00009595 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009596 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9597 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00009598 }
9599 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009600 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9601 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009602}
9603
William M. Brack3d426662005-04-19 14:40:28 +00009604/*
9605 * To assure working code on multiple platforms, we want to only depend
9606 * upon the characteristic truncation of converting a floating point value
9607 * to an integer. Unfortunately, because of the different storage sizes
9608 * of our internal floating point value (double) and integer (int), we
9609 * can't directly convert (see bug 301162). This macro is a messy
9610 * 'workaround'
9611 */
9612#define XTRUNC(f, v) \
9613 f = fmod((v), INT_MAX); \
9614 f = (v) - (f) + (double)((int)(f));
9615
Owen Taylor3473f882001-02-23 17:55:21 +00009616/**
9617 * xmlXPathFloorFunction:
9618 * @ctxt: the XPath Parser context
9619 * @nargs: the number of arguments
9620 *
9621 * Implement the floor() XPath function
9622 * number floor(number)
9623 * The floor function returns the largest (closest to positive infinity)
9624 * number that is not greater than the argument and that is an integer.
9625 */
9626void
9627xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009628 double f;
9629
Owen Taylor3473f882001-02-23 17:55:21 +00009630 CHECK_ARITY(1);
9631 CAST_TO_NUMBER;
9632 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009633
William M. Brack3d426662005-04-19 14:40:28 +00009634 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009635 if (f != ctxt->value->floatval) {
9636 if (ctxt->value->floatval > 0)
9637 ctxt->value->floatval = f;
9638 else
9639 ctxt->value->floatval = f - 1;
9640 }
Owen Taylor3473f882001-02-23 17:55:21 +00009641}
9642
9643/**
9644 * xmlXPathCeilingFunction:
9645 * @ctxt: the XPath Parser context
9646 * @nargs: the number of arguments
9647 *
9648 * Implement the ceiling() XPath function
9649 * number ceiling(number)
9650 * The ceiling function returns the smallest (closest to negative infinity)
9651 * number that is not less than the argument and that is an integer.
9652 */
9653void
9654xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9655 double f;
9656
9657 CHECK_ARITY(1);
9658 CAST_TO_NUMBER;
9659 CHECK_TYPE(XPATH_NUMBER);
9660
9661#if 0
9662 ctxt->value->floatval = ceil(ctxt->value->floatval);
9663#else
William M. Brack3d426662005-04-19 14:40:28 +00009664 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009665 if (f != ctxt->value->floatval) {
9666 if (ctxt->value->floatval > 0)
9667 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009668 else {
9669 if (ctxt->value->floatval < 0 && f == 0)
9670 ctxt->value->floatval = xmlXPathNZERO;
9671 else
9672 ctxt->value->floatval = f;
9673 }
9674
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009675 }
Owen Taylor3473f882001-02-23 17:55:21 +00009676#endif
9677}
9678
9679/**
9680 * xmlXPathRoundFunction:
9681 * @ctxt: the XPath Parser context
9682 * @nargs: the number of arguments
9683 *
9684 * Implement the round() XPath function
9685 * number round(number)
9686 * The round function returns the number that is closest to the
9687 * argument and that is an integer. If there are two such numbers,
9688 * then the one that is even is returned.
9689 */
9690void
9691xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9692 double f;
9693
9694 CHECK_ARITY(1);
9695 CAST_TO_NUMBER;
9696 CHECK_TYPE(XPATH_NUMBER);
9697
Daniel Veillardcda96922001-08-21 10:56:31 +00009698 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9699 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9700 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009701 (ctxt->value->floatval == 0.0))
9702 return;
9703
William M. Brack3d426662005-04-19 14:40:28 +00009704 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009705 if (ctxt->value->floatval < 0) {
9706 if (ctxt->value->floatval < f - 0.5)
9707 ctxt->value->floatval = f - 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009708 else
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009709 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009710 if (ctxt->value->floatval == 0)
9711 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009712 } else {
9713 if (ctxt->value->floatval < f + 0.5)
9714 ctxt->value->floatval = f;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009715 else
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009716 ctxt->value->floatval = f + 1;
9717 }
Owen Taylor3473f882001-02-23 17:55:21 +00009718}
9719
9720/************************************************************************
9721 * *
9722 * The Parser *
9723 * *
9724 ************************************************************************/
9725
9726/*
William M. Brack08171912003-12-29 02:52:11 +00009727 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00009728 * implementation.
9729 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009730static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009731static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009732static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009733static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00009734static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9735 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00009736
9737/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00009738 * xmlXPathCurrentChar:
9739 * @ctxt: the XPath parser context
9740 * @cur: pointer to the beginning of the char
9741 * @len: pointer to the length of the char read
9742 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009743 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00009744 * bytes in the input buffer.
9745 *
Daniel Veillard60087f32001-10-10 09:45:09 +00009746 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00009747 */
9748
9749static int
9750xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9751 unsigned char c;
9752 unsigned int val;
9753 const xmlChar *cur;
9754
9755 if (ctxt == NULL)
9756 return(0);
9757 cur = ctxt->cur;
9758
9759 /*
9760 * We are supposed to handle UTF8, check it's valid
9761 * From rfc2044: encoding of the Unicode values on UTF-8:
9762 *
9763 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9764 * 0000 0000-0000 007F 0xxxxxxx
9765 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
Daniel Veillard45490ae2008-07-29 09:13:19 +00009766 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
Daniel Veillard61d80a22001-04-27 17:13:01 +00009767 *
9768 * Check for the 0x110000 limit too
9769 */
9770 c = *cur;
9771 if (c & 0x80) {
9772 if ((cur[1] & 0xc0) != 0x80)
9773 goto encoding_error;
9774 if ((c & 0xe0) == 0xe0) {
9775
9776 if ((cur[2] & 0xc0) != 0x80)
9777 goto encoding_error;
9778 if ((c & 0xf0) == 0xf0) {
9779 if (((c & 0xf8) != 0xf0) ||
9780 ((cur[3] & 0xc0) != 0x80))
9781 goto encoding_error;
9782 /* 4-byte code */
9783 *len = 4;
9784 val = (cur[0] & 0x7) << 18;
9785 val |= (cur[1] & 0x3f) << 12;
9786 val |= (cur[2] & 0x3f) << 6;
9787 val |= cur[3] & 0x3f;
9788 } else {
9789 /* 3-byte code */
9790 *len = 3;
9791 val = (cur[0] & 0xf) << 12;
9792 val |= (cur[1] & 0x3f) << 6;
9793 val |= cur[2] & 0x3f;
9794 }
9795 } else {
9796 /* 2-byte code */
9797 *len = 2;
9798 val = (cur[0] & 0x1f) << 6;
9799 val |= cur[1] & 0x3f;
9800 }
9801 if (!IS_CHAR(val)) {
9802 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009803 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00009804 return(val);
9805 } else {
9806 /* 1-byte code */
9807 *len = 1;
9808 return((int) *cur);
9809 }
9810encoding_error:
9811 /*
William M. Brack08171912003-12-29 02:52:11 +00009812 * If we detect an UTF8 error that probably means that the
9813 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00009814 * declaration header. Report the error and switch the encoding
9815 * to ISO-Latin-1 (if you don't like this policy, just declare the
9816 * encoding !)
9817 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00009818 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00009819 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009820}
9821
9822/**
Owen Taylor3473f882001-02-23 17:55:21 +00009823 * xmlXPathParseNCName:
9824 * @ctxt: the XPath Parser context
9825 *
9826 * parse an XML namespace non qualified name.
9827 *
9828 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9829 *
9830 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9831 * CombiningChar | Extender
9832 *
9833 * Returns the namespace name or NULL
9834 */
9835
9836xmlChar *
9837xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00009838 const xmlChar *in;
9839 xmlChar *ret;
9840 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009841
Daniel Veillarda82b1822004-11-08 16:24:57 +00009842 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00009843 /*
9844 * Accelerator for simple ASCII names
9845 */
9846 in = ctxt->cur;
9847 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9848 ((*in >= 0x41) && (*in <= 0x5A)) ||
9849 (*in == '_')) {
9850 in++;
9851 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9852 ((*in >= 0x41) && (*in <= 0x5A)) ||
9853 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00009854 (*in == '_') || (*in == '.') ||
9855 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00009856 in++;
9857 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9858 (*in == '[') || (*in == ']') || (*in == ':') ||
9859 (*in == '@') || (*in == '*')) {
9860 count = in - ctxt->cur;
9861 if (count == 0)
9862 return(NULL);
9863 ret = xmlStrndup(ctxt->cur, count);
9864 ctxt->cur = in;
9865 return(ret);
9866 }
9867 }
9868 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009869}
9870
Daniel Veillard2156a562001-04-28 12:24:34 +00009871
Owen Taylor3473f882001-02-23 17:55:21 +00009872/**
9873 * xmlXPathParseQName:
9874 * @ctxt: the XPath Parser context
Daniel Veillard45490ae2008-07-29 09:13:19 +00009875 * @prefix: a xmlChar **
Owen Taylor3473f882001-02-23 17:55:21 +00009876 *
9877 * parse an XML qualified name
9878 *
9879 * [NS 5] QName ::= (Prefix ':')? LocalPart
9880 *
9881 * [NS 6] Prefix ::= NCName
9882 *
9883 * [NS 7] LocalPart ::= NCName
9884 *
9885 * Returns the function returns the local part, and prefix is updated
9886 * to get the Prefix if any.
9887 */
9888
Daniel Veillard56a4cb82001-03-24 17:00:36 +00009889static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00009890xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9891 xmlChar *ret = NULL;
9892
9893 *prefix = NULL;
9894 ret = xmlXPathParseNCName(ctxt);
Daniel Veillard074f37e2008-09-01 13:38:22 +00009895 if (ret && CUR == ':') {
Owen Taylor3473f882001-02-23 17:55:21 +00009896 *prefix = ret;
9897 NEXT;
9898 ret = xmlXPathParseNCName(ctxt);
9899 }
9900 return(ret);
9901}
9902
9903/**
9904 * xmlXPathParseName:
9905 * @ctxt: the XPath Parser context
9906 *
9907 * parse an XML name
9908 *
9909 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9910 * CombiningChar | Extender
9911 *
9912 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9913 *
9914 * Returns the namespace name or NULL
9915 */
9916
9917xmlChar *
9918xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009919 const xmlChar *in;
9920 xmlChar *ret;
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009921 size_t count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009922
Daniel Veillarda82b1822004-11-08 16:24:57 +00009923 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009924 /*
9925 * Accelerator for simple ASCII names
9926 */
9927 in = ctxt->cur;
9928 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9929 ((*in >= 0x41) && (*in <= 0x5A)) ||
9930 (*in == '_') || (*in == ':')) {
9931 in++;
9932 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9933 ((*in >= 0x41) && (*in <= 0x5A)) ||
9934 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00009935 (*in == '_') || (*in == '-') ||
9936 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00009937 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00009938 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009939 count = in - ctxt->cur;
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009940 if (count > XML_MAX_NAME_LENGTH) {
9941 ctxt->cur = in;
9942 XP_ERRORNULL(XPATH_EXPR_ERROR);
9943 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00009944 ret = xmlStrndup(ctxt->cur, count);
9945 ctxt->cur = in;
9946 return(ret);
9947 }
9948 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009949 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009950}
9951
Daniel Veillard61d80a22001-04-27 17:13:01 +00009952static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00009953xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009954 xmlChar buf[XML_MAX_NAMELEN + 5];
9955 int len = 0, l;
9956 int c;
9957
9958 /*
9959 * Handler for more complex cases
9960 */
9961 c = CUR_CHAR(l);
9962 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00009963 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9964 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00009965 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00009966 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009967 return(NULL);
9968 }
9969
9970 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9971 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9972 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00009973 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009974 (IS_COMBINING(c)) ||
9975 (IS_EXTENDER(c)))) {
9976 COPY_BUF(l,buf,len,c);
9977 NEXTL(l);
9978 c = CUR_CHAR(l);
9979 if (len >= XML_MAX_NAMELEN) {
9980 /*
9981 * Okay someone managed to make a huge name, so he's ready to pay
9982 * for the processing speed.
9983 */
9984 xmlChar *buffer;
9985 int max = len * 2;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009986
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009987 if (len > XML_MAX_NAME_LENGTH) {
9988 XP_ERRORNULL(XPATH_EXPR_ERROR);
9989 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00009990 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009991 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009992 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009993 }
9994 memcpy(buffer, buf, len);
9995 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9996 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00009997 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009998 (IS_COMBINING(c)) ||
9999 (IS_EXTENDER(c))) {
10000 if (len + 10 > max) {
Daniel Veillardcd852ad2012-07-30 10:12:18 +080010001 if (max > XML_MAX_NAME_LENGTH) {
10002 XP_ERRORNULL(XPATH_EXPR_ERROR);
10003 }
Daniel Veillard61d80a22001-04-27 17:13:01 +000010004 max *= 2;
10005 buffer = (xmlChar *) xmlRealloc(buffer,
10006 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +000010007 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010008 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +000010009 }
10010 }
10011 COPY_BUF(l,buffer,len,c);
10012 NEXTL(l);
10013 c = CUR_CHAR(l);
10014 }
10015 buffer[len] = 0;
10016 return(buffer);
10017 }
10018 }
Daniel Veillard2156a562001-04-28 12:24:34 +000010019 if (len == 0)
10020 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +000010021 return(xmlStrndup(buf, len));
10022}
Daniel Veillard3cd72402002-05-13 10:33:30 +000010023
10024#define MAX_FRAC 20
10025
William M. Brack372a4452004-02-17 13:09:23 +000010026/*
10027 * These are used as divisors for the fractional part of a number.
10028 * Since the table includes 1.0 (representing '0' fractional digits),
10029 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
10030 */
10031static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +000010032 1.0, 10.0, 100.0, 1000.0, 10000.0,
10033 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
10034 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
10035 100000000000000.0,
10036 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +000010037 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +000010038};
10039
Owen Taylor3473f882001-02-23 17:55:21 +000010040/**
10041 * xmlXPathStringEvalNumber:
10042 * @str: A string to scan
10043 *
Bjorn Reese70a9da52001-04-21 16:57:29 +000010044 * [30a] Float ::= Number ('e' Digits?)?
10045 *
Owen Taylor3473f882001-02-23 17:55:21 +000010046 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard45490ae2008-07-29 09:13:19 +000010047 * | '.' Digits
Owen Taylor3473f882001-02-23 17:55:21 +000010048 * [31] Digits ::= [0-9]+
10049 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010050 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +000010051 * In complement of the Number expression, this function also handles
10052 * negative values : '-' Number.
10053 *
10054 * Returns the double value.
10055 */
10056double
10057xmlXPathStringEvalNumber(const xmlChar *str) {
10058 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +000010059 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010060 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010061 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010062 int exponent = 0;
10063 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010064#ifdef __GNUC__
10065 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010066 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010067#endif
Daniel Veillardeca82812002-04-24 11:42:02 +000010068 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +000010069 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010070 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
10071 return(xmlXPathNAN);
10072 }
10073 if (*cur == '-') {
10074 isneg = 1;
10075 cur++;
10076 }
Daniel Veillardb06c6142001-08-27 14:26:30 +000010077
10078#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010079 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010080 * tmp/temp is a workaround against a gcc compiler bug
10081 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010082 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010083 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010084 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010085 ret = ret * 10;
10086 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +000010087 ok = 1;
10088 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +000010089 temp = (double) tmp;
10090 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010091 }
Daniel Veillardb06c6142001-08-27 14:26:30 +000010092#else
Daniel Veillard7b416132002-03-07 08:36:03 +000010093 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010094 while ((*cur >= '0') && (*cur <= '9')) {
10095 ret = ret * 10 + (*cur - '0');
10096 ok = 1;
10097 cur++;
10098 }
10099#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010100
Owen Taylor3473f882001-02-23 17:55:21 +000010101 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +000010102 int v, frac = 0;
10103 double fraction = 0;
10104
Owen Taylor3473f882001-02-23 17:55:21 +000010105 cur++;
10106 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10107 return(xmlXPathNAN);
10108 }
Daniel Veillard3cd72402002-05-13 10:33:30 +000010109 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
10110 v = (*cur - '0');
10111 fraction = fraction * 10 + v;
10112 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010113 cur++;
10114 }
Daniel Veillard3cd72402002-05-13 10:33:30 +000010115 fraction /= my_pow10[frac];
10116 ret = ret + fraction;
10117 while ((*cur >= '0') && (*cur <= '9'))
10118 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010119 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010120 if ((*cur == 'e') || (*cur == 'E')) {
10121 cur++;
10122 if (*cur == '-') {
10123 is_exponent_negative = 1;
10124 cur++;
William M. Brack99127052004-05-24 02:52:28 +000010125 } else if (*cur == '+') {
10126 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010127 }
10128 while ((*cur >= '0') && (*cur <= '9')) {
10129 exponent = exponent * 10 + (*cur - '0');
10130 cur++;
10131 }
10132 }
William M. Brack76e95df2003-10-18 16:20:14 +000010133 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010134 if (*cur != 0) return(xmlXPathNAN);
10135 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010136 if (is_exponent_negative) exponent = -exponent;
10137 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +000010138 return(ret);
10139}
10140
10141/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010142 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +000010143 * @ctxt: the XPath Parser context
10144 *
10145 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard45490ae2008-07-29 09:13:19 +000010146 * | '.' Digits
Owen Taylor3473f882001-02-23 17:55:21 +000010147 * [31] Digits ::= [0-9]+
10148 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010149 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +000010150 *
10151 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010152static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010153xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10154{
Owen Taylor3473f882001-02-23 17:55:21 +000010155 double ret = 0.0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010156 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010157 int exponent = 0;
10158 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010159#ifdef __GNUC__
10160 unsigned long tmp = 0;
10161 double temp;
10162#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010163
10164 CHECK_ERROR;
10165 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10166 XP_ERROR(XPATH_NUMBER_ERROR);
10167 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010168#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010169 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010170 * tmp/temp is a workaround against a gcc compiler bug
10171 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010172 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010173 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010174 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010175 ret = ret * 10;
10176 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010177 ok = 1;
10178 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +000010179 temp = (double) tmp;
10180 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010181 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010182#else
10183 ret = 0;
10184 while ((CUR >= '0') && (CUR <= '9')) {
10185 ret = ret * 10 + (CUR - '0');
10186 ok = 1;
10187 NEXT;
10188 }
10189#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010190 if (CUR == '.') {
Phil Shaferee32ad32010-11-03 20:53:55 +010010191 int v, frac = 0;
10192 double fraction = 0;
10193
Owen Taylor3473f882001-02-23 17:55:21 +000010194 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010195 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10196 XP_ERROR(XPATH_NUMBER_ERROR);
10197 }
Phil Shaferee32ad32010-11-03 20:53:55 +010010198 while ((CUR >= '0') && (CUR <= '9') && (frac < MAX_FRAC)) {
10199 v = (CUR - '0');
10200 fraction = fraction * 10 + v;
10201 frac = frac + 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010202 NEXT;
10203 }
Phil Shaferee32ad32010-11-03 20:53:55 +010010204 fraction /= my_pow10[frac];
10205 ret = ret + fraction;
10206 while ((CUR >= '0') && (CUR <= '9'))
10207 NEXT;
Owen Taylor3473f882001-02-23 17:55:21 +000010208 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010209 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010210 NEXT;
10211 if (CUR == '-') {
10212 is_exponent_negative = 1;
10213 NEXT;
William M. Brack99127052004-05-24 02:52:28 +000010214 } else if (CUR == '+') {
10215 NEXT;
10216 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010217 while ((CUR >= '0') && (CUR <= '9')) {
10218 exponent = exponent * 10 + (CUR - '0');
10219 NEXT;
10220 }
10221 if (is_exponent_negative)
10222 exponent = -exponent;
10223 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +000010224 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010225 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010226 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010227}
10228
10229/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010230 * xmlXPathParseLiteral:
10231 * @ctxt: the XPath Parser context
10232 *
10233 * Parse a Literal
10234 *
10235 * [29] Literal ::= '"' [^"]* '"'
10236 * | "'" [^']* "'"
10237 *
10238 * Returns the value found or NULL in case of error
10239 */
10240static xmlChar *
10241xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10242 const xmlChar *q;
10243 xmlChar *ret = NULL;
10244
10245 if (CUR == '"') {
10246 NEXT;
10247 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010248 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010249 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010250 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010251 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010252 } else {
10253 ret = xmlStrndup(q, CUR_PTR - q);
10254 NEXT;
10255 }
10256 } else if (CUR == '\'') {
10257 NEXT;
10258 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010259 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010260 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010261 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010262 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010263 } else {
10264 ret = xmlStrndup(q, CUR_PTR - q);
10265 NEXT;
10266 }
10267 } else {
Daniel Veillard24505b02005-07-28 23:49:35 +000010268 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010269 }
10270 return(ret);
10271}
10272
10273/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010274 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +000010275 * @ctxt: the XPath Parser context
10276 *
10277 * Parse a Literal and push it on the stack.
10278 *
10279 * [29] Literal ::= '"' [^"]* '"'
10280 * | "'" [^']* "'"
10281 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010282 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +000010283 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010284static void
10285xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010286 const xmlChar *q;
10287 xmlChar *ret = NULL;
10288
10289 if (CUR == '"') {
10290 NEXT;
10291 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010292 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +000010293 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010294 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010295 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10296 } else {
10297 ret = xmlStrndup(q, CUR_PTR - q);
10298 NEXT;
10299 }
10300 } else if (CUR == '\'') {
10301 NEXT;
10302 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010303 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +000010304 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010305 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010306 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10307 } else {
10308 ret = xmlStrndup(q, CUR_PTR - q);
10309 NEXT;
10310 }
10311 } else {
10312 XP_ERROR(XPATH_START_LITERAL_ERROR);
10313 }
10314 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010315 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010316 xmlXPathCacheNewString(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010317 xmlFree(ret);
10318}
10319
10320/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010321 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +000010322 * @ctxt: the XPath Parser context
10323 *
10324 * Parse a VariableReference, evaluate it and push it on the stack.
10325 *
10326 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +000010327 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +000010328 * of any of the types that are possible for the value of an expression,
10329 * and may also be of additional types not specified here.
10330 *
10331 * Early evaluation is possible since:
10332 * The variable bindings [...] used to evaluate a subexpression are
Daniel Veillard45490ae2008-07-29 09:13:19 +000010333 * always the same as those used to evaluate the containing expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010334 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010335 * [36] VariableReference ::= '$' QName
Owen Taylor3473f882001-02-23 17:55:21 +000010336 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010337static void
10338xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010339 xmlChar *name;
10340 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010341
10342 SKIP_BLANKS;
10343 if (CUR != '$') {
10344 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10345 }
10346 NEXT;
10347 name = xmlXPathParseQName(ctxt, &prefix);
10348 if (name == NULL) {
10349 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10350 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010351 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010352 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10353 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010354 SKIP_BLANKS;
Daniel Veillardb3d14912005-09-04 20:47:39 +000010355 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10356 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
10357 }
Owen Taylor3473f882001-02-23 17:55:21 +000010358}
10359
10360/**
10361 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +000010362 * @name: a name string
10363 *
10364 * Is the name given a NodeType one.
10365 *
10366 * [38] NodeType ::= 'comment'
10367 * | 'text'
10368 * | 'processing-instruction'
10369 * | 'node'
10370 *
10371 * Returns 1 if true 0 otherwise
10372 */
10373int
10374xmlXPathIsNodeType(const xmlChar *name) {
10375 if (name == NULL)
10376 return(0);
10377
Daniel Veillard1971ee22002-01-31 20:29:19 +000010378 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +000010379 return(1);
10380 if (xmlStrEqual(name, BAD_CAST "text"))
10381 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010382 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +000010383 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010384 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +000010385 return(1);
10386 return(0);
10387}
10388
10389/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010390 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +000010391 * @ctxt: the XPath Parser context
10392 *
10393 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010394 * [17] Argument ::= Expr
Owen Taylor3473f882001-02-23 17:55:21 +000010395 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010396 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +000010397 * pushed on the stack
10398 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010399static void
10400xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010401 xmlChar *name;
10402 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010403 int nbargs = 0;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010404 int sort = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010405
10406 name = xmlXPathParseQName(ctxt, &prefix);
10407 if (name == NULL) {
Daniel Veillard074f37e2008-09-01 13:38:22 +000010408 xmlFree(prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010409 XP_ERROR(XPATH_EXPR_ERROR);
10410 }
10411 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010412#ifdef DEBUG_EXPR
10413 if (prefix == NULL)
10414 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10415 name);
10416 else
10417 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10418 prefix, name);
10419#endif
10420
Owen Taylor3473f882001-02-23 17:55:21 +000010421 if (CUR != '(') {
10422 XP_ERROR(XPATH_EXPR_ERROR);
10423 }
10424 NEXT;
10425 SKIP_BLANKS;
10426
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010427 /*
10428 * Optimization for count(): we don't need the node-set to be sorted.
10429 */
10430 if ((prefix == NULL) && (name[0] == 'c') &&
10431 xmlStrEqual(name, BAD_CAST "count"))
10432 {
10433 sort = 0;
10434 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010435 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +000010436 if (CUR != ')') {
10437 while (CUR != 0) {
10438 int op1 = ctxt->comp->last;
10439 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010440 xmlXPathCompileExpr(ctxt, sort);
Daniel Veillard074f37e2008-09-01 13:38:22 +000010441 if (ctxt->error != XPATH_EXPRESSION_OK) {
10442 xmlFree(name);
10443 xmlFree(prefix);
10444 return;
10445 }
Daniel Veillard71f9d732003-01-14 16:07:16 +000010446 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10447 nbargs++;
10448 if (CUR == ')') break;
10449 if (CUR != ',') {
10450 XP_ERROR(XPATH_EXPR_ERROR);
10451 }
10452 NEXT;
10453 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010454 }
Owen Taylor3473f882001-02-23 17:55:21 +000010455 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010456 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10457 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010458 NEXT;
10459 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010460}
10461
10462/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010463 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010464 * @ctxt: the XPath Parser context
10465 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010466 * [15] PrimaryExpr ::= VariableReference
Owen Taylor3473f882001-02-23 17:55:21 +000010467 * | '(' Expr ')'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010468 * | Literal
10469 * | Number
10470 * | FunctionCall
Owen Taylor3473f882001-02-23 17:55:21 +000010471 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010472 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010473 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010474static void
10475xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010476 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010477 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010478 else if (CUR == '(') {
10479 NEXT;
10480 SKIP_BLANKS;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010481 xmlXPathCompileExpr(ctxt, 1);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010482 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000010483 if (CUR != ')') {
10484 XP_ERROR(XPATH_EXPR_ERROR);
10485 }
10486 NEXT;
10487 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010488 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010489 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010490 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010491 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010492 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010493 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010494 }
10495 SKIP_BLANKS;
10496}
10497
10498/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010499 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010500 * @ctxt: the XPath Parser context
10501 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010502 * [20] FilterExpr ::= PrimaryExpr
10503 * | FilterExpr Predicate
Owen Taylor3473f882001-02-23 17:55:21 +000010504 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010505 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010506 * Square brackets are used to filter expressions in the same way that
10507 * they are used in location paths. It is an error if the expression to
10508 * be filtered does not evaluate to a node-set. The context node list
10509 * used for evaluating the expression in square brackets is the node-set
10510 * to be filtered listed in document order.
10511 */
10512
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010513static void
10514xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10515 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010516 CHECK_ERROR;
10517 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010518
Owen Taylor3473f882001-02-23 17:55:21 +000010519 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010520 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +000010521 SKIP_BLANKS;
10522 }
10523
Daniel Veillard45490ae2008-07-29 09:13:19 +000010524
Owen Taylor3473f882001-02-23 17:55:21 +000010525}
10526
10527/**
10528 * xmlXPathScanName:
10529 * @ctxt: the XPath Parser context
10530 *
10531 * Trickery: parse an XML name but without consuming the input flow
10532 * Needed to avoid insanity in the parser state.
10533 *
10534 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10535 * CombiningChar | Extender
10536 *
10537 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10538 *
10539 * [6] Names ::= Name (S Name)*
10540 *
10541 * Returns the Name parsed or NULL
10542 */
10543
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010544static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +000010545xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +000010546 int len = 0, l;
10547 int c;
Daniel Veillard03226812004-11-01 14:55:21 +000010548 const xmlChar *cur;
10549 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +000010550
Daniel Veillard03226812004-11-01 14:55:21 +000010551 cur = ctxt->cur;
10552
10553 c = CUR_CHAR(l);
10554 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10555 (!IS_LETTER(c) && (c != '_') &&
10556 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010557 return(NULL);
10558 }
10559
Daniel Veillard03226812004-11-01 14:55:21 +000010560 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10561 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10562 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000010563 (c == '_') || (c == ':') ||
Daniel Veillard03226812004-11-01 14:55:21 +000010564 (IS_COMBINING(c)) ||
10565 (IS_EXTENDER(c)))) {
10566 len += l;
10567 NEXTL(l);
10568 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +000010569 }
Daniel Veillard03226812004-11-01 14:55:21 +000010570 ret = xmlStrndup(cur, ctxt->cur - cur);
10571 ctxt->cur = cur;
10572 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +000010573}
10574
10575/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010576 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010577 * @ctxt: the XPath Parser context
10578 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010579 * [19] PathExpr ::= LocationPath
10580 * | FilterExpr
10581 * | FilterExpr '/' RelativeLocationPath
10582 * | FilterExpr '//' RelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000010583 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010584 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010585 * The / operator and // operators combine an arbitrary expression
10586 * and a relative location path. It is an error if the expression
10587 * does not evaluate to a node-set.
10588 * The / operator does composition in the same way as when / is
10589 * used in a location path. As in location paths, // is short for
10590 * /descendant-or-self::node()/.
10591 */
10592
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010593static void
10594xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010595 int lc = 1; /* Should we branch to LocationPath ? */
10596 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10597
10598 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010599 if ((CUR == '$') || (CUR == '(') ||
10600 (IS_ASCII_DIGIT(CUR)) ||
William M. Brackd1757ab2004-10-02 22:07:48 +000010601 (CUR == '\'') || (CUR == '"') ||
10602 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010603 lc = 0;
10604 } else if (CUR == '*') {
10605 /* relative or absolute location path */
10606 lc = 1;
10607 } else if (CUR == '/') {
10608 /* relative or absolute location path */
10609 lc = 1;
10610 } else if (CUR == '@') {
10611 /* relative abbreviated attribute location path */
10612 lc = 1;
10613 } else if (CUR == '.') {
10614 /* relative abbreviated attribute location path */
10615 lc = 1;
10616 } else {
10617 /*
10618 * Problem is finding if we have a name here whether it's:
10619 * - a nodetype
10620 * - a function call in which case it's followed by '('
10621 * - an axis in which case it's followed by ':'
10622 * - a element name
10623 * We do an a priori analysis here rather than having to
10624 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +000010625 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +000010626 * read/write/debug.
10627 */
10628 SKIP_BLANKS;
10629 name = xmlXPathScanName(ctxt);
10630 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10631#ifdef DEBUG_STEP
10632 xmlGenericError(xmlGenericErrorContext,
10633 "PathExpr: Axis\n");
10634#endif
10635 lc = 1;
10636 xmlFree(name);
10637 } else if (name != NULL) {
10638 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +000010639
Daniel Veillard45490ae2008-07-29 09:13:19 +000010640
Owen Taylor3473f882001-02-23 17:55:21 +000010641 while (NXT(len) != 0) {
10642 if (NXT(len) == '/') {
10643 /* element name */
10644#ifdef DEBUG_STEP
10645 xmlGenericError(xmlGenericErrorContext,
10646 "PathExpr: AbbrRelLocation\n");
10647#endif
10648 lc = 1;
10649 break;
William M. Brack76e95df2003-10-18 16:20:14 +000010650 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +000010651 /* ignore blanks */
10652 ;
Owen Taylor3473f882001-02-23 17:55:21 +000010653 } else if (NXT(len) == ':') {
10654#ifdef DEBUG_STEP
10655 xmlGenericError(xmlGenericErrorContext,
10656 "PathExpr: AbbrRelLocation\n");
10657#endif
10658 lc = 1;
10659 break;
10660 } else if ((NXT(len) == '(')) {
10661 /* Note Type or Function */
10662 if (xmlXPathIsNodeType(name)) {
10663#ifdef DEBUG_STEP
10664 xmlGenericError(xmlGenericErrorContext,
10665 "PathExpr: Type search\n");
10666#endif
10667 lc = 1;
10668 } else {
10669#ifdef DEBUG_STEP
10670 xmlGenericError(xmlGenericErrorContext,
10671 "PathExpr: function call\n");
10672#endif
10673 lc = 0;
10674 }
10675 break;
10676 } else if ((NXT(len) == '[')) {
10677 /* element name */
10678#ifdef DEBUG_STEP
10679 xmlGenericError(xmlGenericErrorContext,
10680 "PathExpr: AbbrRelLocation\n");
10681#endif
10682 lc = 1;
10683 break;
10684 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10685 (NXT(len) == '=')) {
10686 lc = 1;
10687 break;
10688 } else {
10689 lc = 1;
10690 break;
10691 }
10692 len++;
10693 }
10694 if (NXT(len) == 0) {
10695#ifdef DEBUG_STEP
10696 xmlGenericError(xmlGenericErrorContext,
10697 "PathExpr: AbbrRelLocation\n");
10698#endif
10699 /* element name */
10700 lc = 1;
10701 }
10702 xmlFree(name);
10703 } else {
William M. Brack08171912003-12-29 02:52:11 +000010704 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +000010705 XP_ERROR(XPATH_EXPR_ERROR);
10706 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000010707 }
Owen Taylor3473f882001-02-23 17:55:21 +000010708
10709 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010710 if (CUR == '/') {
10711 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10712 } else {
10713 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010714 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010715 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010716 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010717 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010718 CHECK_ERROR;
10719 if ((CUR == '/') && (NXT(1) == '/')) {
10720 SKIP(2);
10721 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010722
10723 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10724 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10725 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10726
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010727 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010728 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010729 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010730 }
10731 }
10732 SKIP_BLANKS;
10733}
10734
10735/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010736 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010737 * @ctxt: the XPath Parser context
10738 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010739 * [18] UnionExpr ::= PathExpr
10740 * | UnionExpr '|' PathExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010741 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010742 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010743 */
10744
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010745static void
10746xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10747 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010748 CHECK_ERROR;
10749 SKIP_BLANKS;
10750 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010751 int op1 = ctxt->comp->last;
10752 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010753
10754 NEXT;
10755 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010756 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010757
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010758 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10759
Owen Taylor3473f882001-02-23 17:55:21 +000010760 SKIP_BLANKS;
10761 }
Owen Taylor3473f882001-02-23 17:55:21 +000010762}
10763
10764/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010765 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010766 * @ctxt: the XPath Parser context
10767 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010768 * [27] UnaryExpr ::= UnionExpr
10769 * | '-' UnaryExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010770 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010771 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010772 */
10773
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010774static void
10775xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010776 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010777 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010778
10779 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +000010780 while (CUR == '-') {
10781 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010782 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010783 NEXT;
10784 SKIP_BLANKS;
10785 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010786
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010787 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010788 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010789 if (found) {
10790 if (minus)
10791 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10792 else
10793 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010794 }
10795}
10796
10797/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010798 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010799 * @ctxt: the XPath Parser context
10800 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010801 * [26] MultiplicativeExpr ::= UnaryExpr
10802 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10803 * | MultiplicativeExpr 'div' UnaryExpr
10804 * | MultiplicativeExpr 'mod' UnaryExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010805 * [34] MultiplyOperator ::= '*'
10806 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010807 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010808 */
10809
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010810static void
10811xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10812 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010813 CHECK_ERROR;
10814 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010815 while ((CUR == '*') ||
Owen Taylor3473f882001-02-23 17:55:21 +000010816 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10817 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10818 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010819 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010820
10821 if (CUR == '*') {
10822 op = 0;
10823 NEXT;
10824 } else if (CUR == 'd') {
10825 op = 1;
10826 SKIP(3);
10827 } else if (CUR == 'm') {
10828 op = 2;
10829 SKIP(3);
10830 }
10831 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010832 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010833 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010834 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010835 SKIP_BLANKS;
10836 }
10837}
10838
10839/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010840 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010841 * @ctxt: the XPath Parser context
10842 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010843 * [25] AdditiveExpr ::= MultiplicativeExpr
10844 * | AdditiveExpr '+' MultiplicativeExpr
10845 * | AdditiveExpr '-' MultiplicativeExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010846 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010847 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010848 */
10849
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010850static void
10851xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010852
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010853 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010854 CHECK_ERROR;
10855 SKIP_BLANKS;
10856 while ((CUR == '+') || (CUR == '-')) {
10857 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010858 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010859
10860 if (CUR == '+') plus = 1;
10861 else plus = 0;
10862 NEXT;
10863 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010864 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010865 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010866 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010867 SKIP_BLANKS;
10868 }
10869}
10870
10871/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010872 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010873 * @ctxt: the XPath Parser context
10874 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010875 * [24] RelationalExpr ::= AdditiveExpr
10876 * | RelationalExpr '<' AdditiveExpr
10877 * | RelationalExpr '>' AdditiveExpr
10878 * | RelationalExpr '<=' AdditiveExpr
10879 * | RelationalExpr '>=' AdditiveExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010880 *
10881 * A <= B > C is allowed ? Answer from James, yes with
10882 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10883 * which is basically what got implemented.
10884 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010885 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +000010886 * on the stack
10887 */
10888
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010889static void
10890xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10891 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010892 CHECK_ERROR;
10893 SKIP_BLANKS;
10894 while ((CUR == '<') ||
10895 (CUR == '>') ||
10896 ((CUR == '<') && (NXT(1) == '=')) ||
10897 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010898 int inf, strict;
10899 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010900
10901 if (CUR == '<') inf = 1;
10902 else inf = 0;
10903 if (NXT(1) == '=') strict = 0;
10904 else strict = 1;
10905 NEXT;
10906 if (!strict) NEXT;
10907 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010908 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010909 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010910 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +000010911 SKIP_BLANKS;
10912 }
10913}
10914
10915/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010916 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010917 * @ctxt: the XPath Parser context
10918 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010919 * [23] EqualityExpr ::= RelationalExpr
10920 * | EqualityExpr '=' RelationalExpr
10921 * | EqualityExpr '!=' RelationalExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010922 *
10923 * A != B != C is allowed ? Answer from James, yes with
10924 * (RelationalExpr = RelationalExpr) = RelationalExpr
10925 * (RelationalExpr != RelationalExpr) != RelationalExpr
10926 * which is basically what got implemented.
10927 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010928 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010929 *
10930 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010931static void
10932xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10933 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010934 CHECK_ERROR;
10935 SKIP_BLANKS;
10936 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010937 int eq;
10938 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010939
10940 if (CUR == '=') eq = 1;
10941 else eq = 0;
10942 NEXT;
10943 if (!eq) NEXT;
10944 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010945 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010946 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010947 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010948 SKIP_BLANKS;
10949 }
10950}
10951
10952/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010953 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010954 * @ctxt: the XPath Parser context
10955 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010956 * [22] AndExpr ::= EqualityExpr
10957 * | AndExpr 'and' EqualityExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010958 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010959 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010960 *
10961 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010962static void
10963xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10964 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010965 CHECK_ERROR;
10966 SKIP_BLANKS;
10967 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010968 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010969 SKIP(3);
10970 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010971 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010972 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010973 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010974 SKIP_BLANKS;
10975 }
10976}
10977
10978/**
Daniel Veillard591b4be2003-02-09 23:33:36 +000010979 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010980 * @ctxt: the XPath Parser context
10981 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010982 * [14] Expr ::= OrExpr
10983 * [21] OrExpr ::= AndExpr
10984 * | OrExpr 'or' AndExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010985 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010986 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +000010987 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010988static void
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010989xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010990 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010991 CHECK_ERROR;
10992 SKIP_BLANKS;
10993 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010994 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010995 SKIP(2);
10996 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010997 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010998 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010999 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011000 SKIP_BLANKS;
11001 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011002 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011003 /* more ops could be optimized too */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011004 /*
11005 * This is the main place to eliminate sorting for
11006 * operations which don't require a sorted node-set.
11007 * E.g. count().
11008 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011009 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
11010 }
Owen Taylor3473f882001-02-23 17:55:21 +000011011}
11012
11013/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011014 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +000011015 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011016 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +000011017 *
11018 * [8] Predicate ::= '[' PredicateExpr ']'
Daniel Veillard45490ae2008-07-29 09:13:19 +000011019 * [9] PredicateExpr ::= Expr
Owen Taylor3473f882001-02-23 17:55:21 +000011020 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011021 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +000011022 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011023static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011024xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011025 int op1 = ctxt->comp->last;
11026
11027 SKIP_BLANKS;
11028 if (CUR != '[') {
11029 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11030 }
11031 NEXT;
11032 SKIP_BLANKS;
11033
11034 ctxt->comp->last = -1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011035 /*
11036 * This call to xmlXPathCompileExpr() will deactivate sorting
11037 * of the predicate result.
11038 * TODO: Sorting is still activated for filters, since I'm not
11039 * sure if needed. Normally sorting should not be needed, since
11040 * a filter can only diminish the number of items in a sequence,
11041 * but won't change its order; so if the initial sequence is sorted,
11042 * subsequent sorting is not needed.
11043 */
11044 if (! filter)
11045 xmlXPathCompileExpr(ctxt, 0);
11046 else
11047 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011048 CHECK_ERROR;
11049
11050 if (CUR != ']') {
11051 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11052 }
11053
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011054 if (filter)
11055 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11056 else
11057 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011058
11059 NEXT;
11060 SKIP_BLANKS;
11061}
11062
11063/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011064 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +000011065 * @ctxt: the XPath Parser context
11066 * @test: pointer to a xmlXPathTestVal
11067 * @type: pointer to a xmlXPathTypeVal
11068 * @prefix: placeholder for a possible name prefix
11069 *
11070 * [7] NodeTest ::= NameTest
11071 * | NodeType '(' ')'
11072 * | 'processing-instruction' '(' Literal ')'
11073 *
11074 * [37] NameTest ::= '*'
11075 * | NCName ':' '*'
11076 * | QName
11077 * [38] NodeType ::= 'comment'
11078 * | 'text'
11079 * | 'processing-instruction'
11080 * | 'node'
11081 *
William M. Brack08171912003-12-29 02:52:11 +000011082 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +000011083 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011084static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011085xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11086 xmlXPathTypeVal *type, const xmlChar **prefix,
11087 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +000011088 int blanks;
11089
11090 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11091 STRANGE;
11092 return(NULL);
11093 }
William M. Brack78637da2003-07-31 14:47:38 +000011094 *type = (xmlXPathTypeVal) 0;
11095 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011096 *prefix = NULL;
11097 SKIP_BLANKS;
11098
11099 if ((name == NULL) && (CUR == '*')) {
11100 /*
11101 * All elements
11102 */
11103 NEXT;
11104 *test = NODE_TEST_ALL;
11105 return(NULL);
11106 }
11107
11108 if (name == NULL)
11109 name = xmlXPathParseNCName(ctxt);
11110 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011111 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011112 }
11113
William M. Brack76e95df2003-10-18 16:20:14 +000011114 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +000011115 SKIP_BLANKS;
11116 if (CUR == '(') {
11117 NEXT;
11118 /*
11119 * NodeType or PI search
11120 */
11121 if (xmlStrEqual(name, BAD_CAST "comment"))
11122 *type = NODE_TYPE_COMMENT;
11123 else if (xmlStrEqual(name, BAD_CAST "node"))
11124 *type = NODE_TYPE_NODE;
11125 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11126 *type = NODE_TYPE_PI;
11127 else if (xmlStrEqual(name, BAD_CAST "text"))
11128 *type = NODE_TYPE_TEXT;
11129 else {
11130 if (name != NULL)
11131 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000011132 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011133 }
11134
11135 *test = NODE_TEST_TYPE;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011136
Owen Taylor3473f882001-02-23 17:55:21 +000011137 SKIP_BLANKS;
11138 if (*type == NODE_TYPE_PI) {
11139 /*
11140 * Specific case: search a PI by name.
11141 */
Owen Taylor3473f882001-02-23 17:55:21 +000011142 if (name != NULL)
11143 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +000011144 name = NULL;
11145 if (CUR != ')') {
11146 name = xmlXPathParseLiteral(ctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000011147 CHECK_ERROR NULL;
Daniel Veillarded23b7d2002-05-27 12:16:02 +000011148 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +000011149 SKIP_BLANKS;
11150 }
Owen Taylor3473f882001-02-23 17:55:21 +000011151 }
11152 if (CUR != ')') {
11153 if (name != NULL)
11154 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000011155 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011156 }
11157 NEXT;
11158 return(name);
11159 }
11160 *test = NODE_TEST_NAME;
11161 if ((!blanks) && (CUR == ':')) {
11162 NEXT;
11163
11164 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011165 * Since currently the parser context don't have a
11166 * namespace list associated:
11167 * The namespace name for this prefix can be computed
11168 * only at evaluation time. The compilation is done
11169 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +000011170 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011171#if 0
Owen Taylor3473f882001-02-23 17:55:21 +000011172 *prefix = xmlXPathNsLookup(ctxt->context, name);
11173 if (name != NULL)
11174 xmlFree(name);
11175 if (*prefix == NULL) {
11176 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11177 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011178#else
11179 *prefix = name;
11180#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011181
11182 if (CUR == '*') {
11183 /*
11184 * All elements
11185 */
11186 NEXT;
11187 *test = NODE_TEST_ALL;
11188 return(NULL);
11189 }
11190
11191 name = xmlXPathParseNCName(ctxt);
11192 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011193 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011194 }
11195 }
11196 return(name);
11197}
11198
11199/**
11200 * xmlXPathIsAxisName:
11201 * @name: a preparsed name token
11202 *
11203 * [6] AxisName ::= 'ancestor'
11204 * | 'ancestor-or-self'
11205 * | 'attribute'
11206 * | 'child'
11207 * | 'descendant'
11208 * | 'descendant-or-self'
11209 * | 'following'
11210 * | 'following-sibling'
11211 * | 'namespace'
11212 * | 'parent'
11213 * | 'preceding'
11214 * | 'preceding-sibling'
11215 * | 'self'
11216 *
11217 * Returns the axis or 0
11218 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011219static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +000011220xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +000011221 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011222 switch (name[0]) {
11223 case 'a':
11224 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11225 ret = AXIS_ANCESTOR;
11226 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11227 ret = AXIS_ANCESTOR_OR_SELF;
11228 if (xmlStrEqual(name, BAD_CAST "attribute"))
11229 ret = AXIS_ATTRIBUTE;
11230 break;
11231 case 'c':
11232 if (xmlStrEqual(name, BAD_CAST "child"))
11233 ret = AXIS_CHILD;
11234 break;
11235 case 'd':
11236 if (xmlStrEqual(name, BAD_CAST "descendant"))
11237 ret = AXIS_DESCENDANT;
11238 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11239 ret = AXIS_DESCENDANT_OR_SELF;
11240 break;
11241 case 'f':
11242 if (xmlStrEqual(name, BAD_CAST "following"))
11243 ret = AXIS_FOLLOWING;
11244 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11245 ret = AXIS_FOLLOWING_SIBLING;
11246 break;
11247 case 'n':
11248 if (xmlStrEqual(name, BAD_CAST "namespace"))
11249 ret = AXIS_NAMESPACE;
11250 break;
11251 case 'p':
11252 if (xmlStrEqual(name, BAD_CAST "parent"))
11253 ret = AXIS_PARENT;
11254 if (xmlStrEqual(name, BAD_CAST "preceding"))
11255 ret = AXIS_PRECEDING;
11256 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11257 ret = AXIS_PRECEDING_SIBLING;
11258 break;
11259 case 's':
11260 if (xmlStrEqual(name, BAD_CAST "self"))
11261 ret = AXIS_SELF;
11262 break;
11263 }
11264 return(ret);
11265}
11266
11267/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011268 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +000011269 * @ctxt: the XPath Parser context
11270 *
11271 * [4] Step ::= AxisSpecifier NodeTest Predicate*
Daniel Veillard45490ae2008-07-29 09:13:19 +000011272 * | AbbreviatedStep
Owen Taylor3473f882001-02-23 17:55:21 +000011273 *
11274 * [12] AbbreviatedStep ::= '.' | '..'
11275 *
11276 * [5] AxisSpecifier ::= AxisName '::'
11277 * | AbbreviatedAxisSpecifier
11278 *
11279 * [13] AbbreviatedAxisSpecifier ::= '@'?
11280 *
11281 * Modified for XPtr range support as:
11282 *
11283 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11284 * | AbbreviatedStep
11285 * | 'range-to' '(' Expr ')' Predicate*
11286 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011287 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +000011288 * A location step of . is short for self::node(). This is
11289 * particularly useful in conjunction with //. For example, the
11290 * location path .//para is short for
11291 * self::node()/descendant-or-self::node()/child::para
11292 * and so will select all para descendant elements of the context
11293 * node.
11294 * Similarly, a location step of .. is short for parent::node().
11295 * For example, ../title is short for parent::node()/child::title
11296 * and so will select the title children of the parent of the context
11297 * node.
11298 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011299static void
11300xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011301#ifdef LIBXML_XPTR_ENABLED
11302 int rangeto = 0;
11303 int op2 = -1;
11304#endif
11305
Owen Taylor3473f882001-02-23 17:55:21 +000011306 SKIP_BLANKS;
11307 if ((CUR == '.') && (NXT(1) == '.')) {
11308 SKIP(2);
11309 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011310 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11311 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011312 } else if (CUR == '.') {
11313 NEXT;
11314 SKIP_BLANKS;
11315 } else {
11316 xmlChar *name = NULL;
11317 const xmlChar *prefix = NULL;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011318 xmlXPathTestVal test = (xmlXPathTestVal) 0;
William M. Brack78637da2003-07-31 14:47:38 +000011319 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011320 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011321 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +000011322
11323 /*
11324 * The modification needed for XPointer change to the production
11325 */
11326#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011327 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +000011328 name = xmlXPathParseNCName(ctxt);
11329 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011330 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011331 xmlFree(name);
11332 SKIP_BLANKS;
11333 if (CUR != '(') {
11334 XP_ERROR(XPATH_EXPR_ERROR);
11335 }
11336 NEXT;
11337 SKIP_BLANKS;
11338
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011339 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011340 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +000011341 CHECK_ERROR;
11342
11343 SKIP_BLANKS;
11344 if (CUR != ')') {
11345 XP_ERROR(XPATH_EXPR_ERROR);
11346 }
11347 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011348 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000011349 goto eval_predicates;
11350 }
11351 }
11352#endif
Daniel Veillard2156a562001-04-28 12:24:34 +000011353 if (CUR == '*') {
11354 axis = AXIS_CHILD;
11355 } else {
11356 if (name == NULL)
11357 name = xmlXPathParseNCName(ctxt);
11358 if (name != NULL) {
11359 axis = xmlXPathIsAxisName(name);
11360 if (axis != 0) {
11361 SKIP_BLANKS;
11362 if ((CUR == ':') && (NXT(1) == ':')) {
11363 SKIP(2);
11364 xmlFree(name);
11365 name = NULL;
11366 } else {
11367 /* an element name can conflict with an axis one :-\ */
11368 axis = AXIS_CHILD;
11369 }
Owen Taylor3473f882001-02-23 17:55:21 +000011370 } else {
Owen Taylor3473f882001-02-23 17:55:21 +000011371 axis = AXIS_CHILD;
11372 }
Daniel Veillard2156a562001-04-28 12:24:34 +000011373 } else if (CUR == '@') {
11374 NEXT;
11375 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +000011376 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +000011377 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +000011378 }
Owen Taylor3473f882001-02-23 17:55:21 +000011379 }
11380
Daniel Veillard2f3523f2010-10-15 18:30:29 +020011381 if (ctxt->error != XPATH_EXPRESSION_OK) {
11382 xmlFree(name);
11383 return;
11384 }
Owen Taylor3473f882001-02-23 17:55:21 +000011385
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011386 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +000011387 if (test == 0)
11388 return;
11389
Daniel Veillarded6c5492005-07-23 15:00:22 +000011390 if ((prefix != NULL) && (ctxt->context != NULL) &&
11391 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11392 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11393 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11394 }
11395 }
Owen Taylor3473f882001-02-23 17:55:21 +000011396#ifdef DEBUG_STEP
11397 xmlGenericError(xmlGenericErrorContext,
11398 "Basis : computing new set\n");
11399#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011400
Owen Taylor3473f882001-02-23 17:55:21 +000011401#ifdef DEBUG_STEP
11402 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011403 if (ctxt->value == NULL)
11404 xmlGenericError(xmlGenericErrorContext, "no value\n");
11405 else if (ctxt->value->nodesetval == NULL)
11406 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11407 else
11408 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011409#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011410
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011411#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +000011412eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011413#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011414 op1 = ctxt->comp->last;
11415 ctxt->comp->last = -1;
11416
Owen Taylor3473f882001-02-23 17:55:21 +000011417 SKIP_BLANKS;
11418 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011419 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011420 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011421
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011422#ifdef LIBXML_XPTR_ENABLED
11423 if (rangeto) {
11424 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11425 } else
11426#endif
11427 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11428 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011429
Owen Taylor3473f882001-02-23 17:55:21 +000011430 }
11431#ifdef DEBUG_STEP
11432 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011433 if (ctxt->value == NULL)
11434 xmlGenericError(xmlGenericErrorContext, "no value\n");
11435 else if (ctxt->value->nodesetval == NULL)
11436 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11437 else
11438 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11439 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011440#endif
11441}
11442
11443/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011444 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011445 * @ctxt: the XPath Parser context
11446 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011447 * [3] RelativeLocationPath ::= Step
11448 * | RelativeLocationPath '/' Step
11449 * | AbbreviatedRelativeLocationPath
11450 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
Owen Taylor3473f882001-02-23 17:55:21 +000011451 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011452 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +000011453 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011454static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011455xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011456(xmlXPathParserContextPtr ctxt) {
11457 SKIP_BLANKS;
11458 if ((CUR == '/') && (NXT(1) == '/')) {
11459 SKIP(2);
11460 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011461 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11462 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011463 } else if (CUR == '/') {
11464 NEXT;
11465 SKIP_BLANKS;
11466 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011467 xmlXPathCompStep(ctxt);
Martin729601f2009-10-12 22:42:26 +020011468 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000011469 SKIP_BLANKS;
11470 while (CUR == '/') {
11471 if ((CUR == '/') && (NXT(1) == '/')) {
11472 SKIP(2);
11473 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011474 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +000011475 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011476 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011477 } else if (CUR == '/') {
11478 NEXT;
11479 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011480 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011481 }
11482 SKIP_BLANKS;
11483 }
11484}
11485
11486/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011487 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011488 * @ctxt: the XPath Parser context
11489 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011490 * [1] LocationPath ::= RelativeLocationPath
11491 * | AbsoluteLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011492 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
Daniel Veillard45490ae2008-07-29 09:13:19 +000011493 * | AbbreviatedAbsoluteLocationPath
11494 * [10] AbbreviatedAbsoluteLocationPath ::=
11495 * '//' RelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011496 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011497 * Compile a location path
11498 *
Owen Taylor3473f882001-02-23 17:55:21 +000011499 * // is short for /descendant-or-self::node()/. For example,
11500 * //para is short for /descendant-or-self::node()/child::para and
11501 * so will select any para element in the document (even a para element
11502 * that is a document element will be selected by //para since the
11503 * document element node is a child of the root node); div//para is
11504 * short for div/descendant-or-self::node()/child::para and so will
11505 * select all para descendants of div children.
11506 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011507static void
11508xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000011509 SKIP_BLANKS;
11510 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011511 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011512 } else {
11513 while (CUR == '/') {
11514 if ((CUR == '/') && (NXT(1) == '/')) {
11515 SKIP(2);
11516 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011517 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11518 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011519 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011520 } else if (CUR == '/') {
11521 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +000011522 SKIP_BLANKS;
11523 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +000011524 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +000011525 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011526 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011527 }
Martin729601f2009-10-12 22:42:26 +020011528 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000011529 }
11530 }
11531}
11532
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011533/************************************************************************
11534 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011535 * XPath precompiled expression evaluation *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011536 * *
11537 ************************************************************************/
11538
Daniel Veillardf06307e2001-07-03 10:35:50 +000011539static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011540xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11541
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011542#ifdef DEBUG_STEP
11543static void
Daniel Veillard074f37e2008-09-01 13:38:22 +000011544xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011545 int nbNodes)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011546{
Daniel Veillardf06307e2001-07-03 10:35:50 +000011547 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillard074f37e2008-09-01 13:38:22 +000011548 switch (op->value) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011549 case AXIS_ANCESTOR:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011550 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011551 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011552 case AXIS_ANCESTOR_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011553 xmlGenericError(xmlGenericErrorContext,
11554 "axis 'ancestors-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011555 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011556 case AXIS_ATTRIBUTE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011557 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011558 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011559 case AXIS_CHILD:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011560 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011561 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011562 case AXIS_DESCENDANT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011563 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011564 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011565 case AXIS_DESCENDANT_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011566 xmlGenericError(xmlGenericErrorContext,
11567 "axis 'descendant-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011568 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011569 case AXIS_FOLLOWING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011570 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011571 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011572 case AXIS_FOLLOWING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011573 xmlGenericError(xmlGenericErrorContext,
11574 "axis 'following-siblings' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011575 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011576 case AXIS_NAMESPACE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011577 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011578 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011579 case AXIS_PARENT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011580 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011581 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011582 case AXIS_PRECEDING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011583 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011584 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011585 case AXIS_PRECEDING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011586 xmlGenericError(xmlGenericErrorContext,
11587 "axis 'preceding-sibling' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011588 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011589 case AXIS_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011590 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011591 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011592 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011593 xmlGenericError(xmlGenericErrorContext,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011594 " context contains %d nodes\n", nbNodes);
Daniel Veillard074f37e2008-09-01 13:38:22 +000011595 switch (op->value2) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011596 case NODE_TEST_NONE:
11597 xmlGenericError(xmlGenericErrorContext,
11598 " searching for none !!!\n");
11599 break;
11600 case NODE_TEST_TYPE:
11601 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011602 " searching for type %d\n", op->value3);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011603 break;
11604 case NODE_TEST_PI:
11605 xmlGenericError(xmlGenericErrorContext,
11606 " searching for PI !!!\n");
11607 break;
11608 case NODE_TEST_ALL:
11609 xmlGenericError(xmlGenericErrorContext,
11610 " searching for *\n");
11611 break;
11612 case NODE_TEST_NS:
11613 xmlGenericError(xmlGenericErrorContext,
11614 " searching for namespace %s\n",
Daniel Veillard074f37e2008-09-01 13:38:22 +000011615 op->value5);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011616 break;
11617 case NODE_TEST_NAME:
11618 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011619 " searching for name %s\n", op->value5);
11620 if (op->value4)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011621 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011622 " with namespace %s\n", op->value4);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011623 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011624 }
11625 xmlGenericError(xmlGenericErrorContext, "Testing : ");
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011626}
11627#endif /* DEBUG_STEP */
11628
11629static int
11630xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11631 xmlXPathStepOpPtr op,
11632 xmlNodeSetPtr set,
11633 int contextSize,
11634 int hasNsNodes)
11635{
11636 if (op->ch1 != -1) {
11637 xmlXPathCompExprPtr comp = ctxt->comp;
11638 /*
11639 * Process inner predicates first.
11640 */
11641 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11642 /*
11643 * TODO: raise an internal error.
11644 */
11645 }
11646 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11647 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11648 CHECK_ERROR0;
11649 if (contextSize <= 0)
11650 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011651 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011652 if (op->ch2 != -1) {
11653 xmlXPathContextPtr xpctxt = ctxt->context;
11654 xmlNodePtr contextNode, oldContextNode;
11655 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011656 int i, res, contextPos = 0, newContextSize;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011657 xmlXPathStepOpPtr exprOp;
11658 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11659
11660#ifdef LIBXML_XPTR_ENABLED
11661 /*
11662 * URGENT TODO: Check the following:
11663 * We don't expect location sets if evaluating prediates, right?
11664 * Only filters should expect location sets, right?
11665 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011666#endif
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011667 /*
11668 * SPEC XPath 1.0:
11669 * "For each node in the node-set to be filtered, the
11670 * PredicateExpr is evaluated with that node as the
11671 * context node, with the number of nodes in the
11672 * node-set as the context size, and with the proximity
11673 * position of the node in the node-set with respect to
11674 * the axis as the context position;"
11675 * @oldset is the node-set" to be filtered.
11676 *
11677 * SPEC XPath 1.0:
11678 * "only predicates change the context position and
11679 * context size (see [2.4 Predicates])."
11680 * Example:
11681 * node-set context pos
11682 * nA 1
11683 * nB 2
11684 * nC 3
11685 * After applying predicate [position() > 1] :
11686 * node-set context pos
11687 * nB 1
11688 * nC 2
11689 */
11690 oldContextNode = xpctxt->node;
11691 oldContextDoc = xpctxt->doc;
11692 /*
11693 * Get the expression of this predicate.
11694 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000011695 exprOp = &ctxt->comp->steps[op->ch2];
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011696 newContextSize = 0;
11697 for (i = 0; i < set->nodeNr; i++) {
11698 if (set->nodeTab[i] == NULL)
11699 continue;
11700
11701 contextNode = set->nodeTab[i];
11702 xpctxt->node = contextNode;
11703 xpctxt->contextSize = contextSize;
11704 xpctxt->proximityPosition = ++contextPos;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011705
11706 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011707 * Also set the xpath document in case things like
11708 * key() are evaluated in the predicate.
11709 */
11710 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11711 (contextNode->doc != NULL))
11712 xpctxt->doc = contextNode->doc;
11713 /*
11714 * Evaluate the predicate expression with 1 context node
11715 * at a time; this node is packaged into a node set; this
11716 * node set is handed over to the evaluation mechanism.
11717 */
11718 if (contextObj == NULL)
11719 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11720 else
11721 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11722 contextNode);
11723
11724 valuePush(ctxt, contextObj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011725
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011726 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011727
William M. Brack0bcec062007-02-14 02:15:19 +000011728 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11729 xmlXPathNodeSetClear(set, hasNsNodes);
11730 newContextSize = 0;
11731 goto evaluation_exit;
11732 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011733
11734 if (res != 0) {
11735 newContextSize++;
11736 } else {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011737 /*
11738 * Remove the entry from the initial node set.
11739 */
11740 set->nodeTab[i] = NULL;
11741 if (contextNode->type == XML_NAMESPACE_DECL)
11742 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011743 }
11744 if (ctxt->value == contextObj) {
11745 /*
11746 * Don't free the temporary XPath object holding the
11747 * context node, in order to avoid massive recreation
11748 * inside this loop.
11749 */
11750 valuePop(ctxt);
11751 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11752 } else {
11753 /*
11754 * TODO: The object was lost in the evaluation machinery.
11755 * Can this happen? Maybe in internal-error cases.
11756 */
11757 contextObj = NULL;
11758 }
11759 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011760
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011761 if (contextObj != NULL) {
11762 if (ctxt->value == contextObj)
11763 valuePop(ctxt);
11764 xmlXPathReleaseObject(xpctxt, contextObj);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011765 }
William M. Brack0bcec062007-02-14 02:15:19 +000011766evaluation_exit:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011767 if (exprRes != NULL)
11768 xmlXPathReleaseObject(ctxt->context, exprRes);
11769 /*
11770 * Reset/invalidate the context.
11771 */
11772 xpctxt->node = oldContextNode;
11773 xpctxt->doc = oldContextDoc;
11774 xpctxt->contextSize = -1;
11775 xpctxt->proximityPosition = -1;
11776 return(newContextSize);
11777 }
11778 return(contextSize);
11779}
11780
11781static int
11782xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11783 xmlXPathStepOpPtr op,
11784 xmlNodeSetPtr set,
11785 int contextSize,
11786 int minPos,
11787 int maxPos,
11788 int hasNsNodes)
11789{
11790 if (op->ch1 != -1) {
11791 xmlXPathCompExprPtr comp = ctxt->comp;
11792 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11793 /*
11794 * TODO: raise an internal error.
11795 */
11796 }
11797 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11798 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11799 CHECK_ERROR0;
11800 if (contextSize <= 0)
11801 return(0);
11802 }
11803 /*
11804 * Check if the node set contains a sufficient number of nodes for
11805 * the requested range.
11806 */
11807 if (contextSize < minPos) {
11808 xmlXPathNodeSetClear(set, hasNsNodes);
11809 return(0);
11810 }
11811 if (op->ch2 == -1) {
11812 /*
11813 * TODO: Can this ever happen?
11814 */
11815 return (contextSize);
11816 } else {
11817 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011818 int i, pos = 0, newContextSize = 0, contextPos = 0, res;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011819 xmlXPathStepOpPtr exprOp;
11820 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11821 xmlNodePtr oldContextNode, contextNode = NULL;
11822 xmlXPathContextPtr xpctxt = ctxt->context;
Daniel Veillardf5048b32011-08-18 17:10:13 +080011823 int frame;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011824
11825#ifdef LIBXML_XPTR_ENABLED
11826 /*
11827 * URGENT TODO: Check the following:
11828 * We don't expect location sets if evaluating prediates, right?
11829 * Only filters should expect location sets, right?
11830 */
11831#endif /* LIBXML_XPTR_ENABLED */
11832
11833 /*
11834 * Save old context.
11835 */
11836 oldContextNode = xpctxt->node;
11837 oldContextDoc = xpctxt->doc;
11838 /*
11839 * Get the expression of this predicate.
11840 */
11841 exprOp = &ctxt->comp->steps[op->ch2];
11842 for (i = 0; i < set->nodeNr; i++) {
Daniel Veillardf5048b32011-08-18 17:10:13 +080011843 xmlXPathObjectPtr tmp;
11844
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011845 if (set->nodeTab[i] == NULL)
11846 continue;
11847
11848 contextNode = set->nodeTab[i];
11849 xpctxt->node = contextNode;
11850 xpctxt->contextSize = contextSize;
11851 xpctxt->proximityPosition = ++contextPos;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011852
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011853 /*
11854 * Initialize the new set.
11855 * Also set the xpath document in case things like
11856 * key() evaluation are attempted on the predicate
11857 */
11858 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11859 (contextNode->doc != NULL))
11860 xpctxt->doc = contextNode->doc;
11861 /*
11862 * Evaluate the predicate expression with 1 context node
11863 * at a time; this node is packaged into a node set; this
11864 * node set is handed over to the evaluation mechanism.
11865 */
11866 if (contextObj == NULL)
11867 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11868 else
11869 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11870 contextNode);
11871
Daniel Veillardf5048b32011-08-18 17:10:13 +080011872 frame = xmlXPathSetFrame(ctxt);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011873 valuePush(ctxt, contextObj);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011874 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Daniel Veillardf5048b32011-08-18 17:10:13 +080011875 tmp = valuePop(ctxt);
11876 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011877
William M. Brackf1794562007-08-23 12:58:13 +000011878 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
Daniel Veillardf5048b32011-08-18 17:10:13 +080011879 while (tmp != contextObj) {
Daniel Veillarddf83c172010-11-17 14:12:14 +010011880 /*
11881 * Free up the result
11882 * then pop off contextObj, which will be freed later
11883 */
11884 xmlXPathReleaseObject(xpctxt, tmp);
Daniel Veillardf5048b32011-08-18 17:10:13 +080011885 tmp = valuePop(ctxt);
Daniel Veillardfec31bc2010-11-18 11:07:24 +010011886 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011887 goto evaluation_error;
William M. Brackf1794562007-08-23 12:58:13 +000011888 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080011889 /* push the result back onto the stack */
11890 valuePush(ctxt, tmp);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011891
11892 if (res)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011893 pos++;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011894
11895 if (res && (pos >= minPos) && (pos <= maxPos)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011896 /*
11897 * Fits in the requested range.
11898 */
11899 newContextSize++;
11900 if (minPos == maxPos) {
11901 /*
11902 * Only 1 node was requested.
11903 */
11904 if (contextNode->type == XML_NAMESPACE_DECL) {
11905 /*
11906 * As always: take care of those nasty
11907 * namespace nodes.
11908 */
11909 set->nodeTab[i] = NULL;
11910 }
11911 xmlXPathNodeSetClear(set, hasNsNodes);
11912 set->nodeNr = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011913 set->nodeTab[0] = contextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011914 goto evaluation_exit;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011915 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011916 if (pos == maxPos) {
11917 /*
11918 * We are done.
11919 */
11920 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11921 goto evaluation_exit;
11922 }
11923 } else {
11924 /*
11925 * Remove the entry from the initial node set.
11926 */
11927 set->nodeTab[i] = NULL;
11928 if (contextNode->type == XML_NAMESPACE_DECL)
11929 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11930 }
11931 if (exprRes != NULL) {
11932 xmlXPathReleaseObject(ctxt->context, exprRes);
11933 exprRes = NULL;
11934 }
11935 if (ctxt->value == contextObj) {
11936 /*
11937 * Don't free the temporary XPath object holding the
11938 * context node, in order to avoid massive recreation
11939 * inside this loop.
11940 */
11941 valuePop(ctxt);
11942 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11943 } else {
11944 /*
11945 * The object was lost in the evaluation machinery.
11946 * Can this happen? Maybe in case of internal-errors.
11947 */
11948 contextObj = NULL;
11949 }
11950 }
11951 goto evaluation_exit;
11952
11953evaluation_error:
11954 xmlXPathNodeSetClear(set, hasNsNodes);
11955 newContextSize = 0;
11956
11957evaluation_exit:
11958 if (contextObj != NULL) {
11959 if (ctxt->value == contextObj)
11960 valuePop(ctxt);
11961 xmlXPathReleaseObject(xpctxt, contextObj);
11962 }
11963 if (exprRes != NULL)
11964 xmlXPathReleaseObject(ctxt->context, exprRes);
11965 /*
11966 * Reset/invalidate the context.
11967 */
11968 xpctxt->node = oldContextNode;
11969 xpctxt->doc = oldContextDoc;
11970 xpctxt->contextSize = -1;
11971 xpctxt->proximityPosition = -1;
11972 return(newContextSize);
11973 }
11974 return(contextSize);
11975}
11976
11977static int
11978xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
Daniel Veillard45490ae2008-07-29 09:13:19 +000011979 xmlXPathStepOpPtr op,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011980 int *maxPos)
11981{
11982
11983 xmlXPathStepOpPtr exprOp;
11984
11985 /*
11986 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11987 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000011988
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011989 /*
11990 * If not -1, then ch1 will point to:
11991 * 1) For predicates (XPATH_OP_PREDICATE):
11992 * - an inner predicate operator
11993 * 2) For filters (XPATH_OP_FILTER):
11994 * - an inner filter operater OR
11995 * - an expression selecting the node set.
11996 * E.g. "key('a', 'b')" or "(//foo | //bar)".
Daniel Veillard45490ae2008-07-29 09:13:19 +000011997 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011998 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11999 return(0);
12000
12001 if (op->ch2 != -1) {
12002 exprOp = &ctxt->comp->steps[op->ch2];
Daniel Veillard45490ae2008-07-29 09:13:19 +000012003 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012004 return(0);
12005
12006 if ((exprOp != NULL) &&
12007 (exprOp->op == XPATH_OP_VALUE) &&
12008 (exprOp->value4 != NULL) &&
12009 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
12010 {
12011 /*
12012 * We have a "[n]" predicate here.
12013 * TODO: Unfortunately this simplistic test here is not
12014 * able to detect a position() predicate in compound
12015 * expressions like "[@attr = 'a" and position() = 1],
12016 * and even not the usage of position() in
12017 * "[position() = 1]"; thus - obviously - a position-range,
12018 * like it "[position() < 5]", is also not detected.
12019 * Maybe we could rewrite the AST to ease the optimization.
12020 */
12021 *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012022
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012023 if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
12024 (float) *maxPos)
Daniel Veillard45490ae2008-07-29 09:13:19 +000012025 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012026 return(1);
12027 }
12028 }
12029 return(0);
12030}
12031
12032static int
12033xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
12034 xmlXPathStepOpPtr op,
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012035 xmlNodePtr * first, xmlNodePtr * last,
12036 int toBool)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012037{
12038
12039#define XP_TEST_HIT \
12040 if (hasAxisRange != 0) { \
12041 if (++pos == maxPos) { \
12042 addNode(seq, cur); \
12043 goto axis_range_end; } \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012044 } else { \
12045 addNode(seq, cur); \
12046 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012047
12048#define XP_TEST_HIT_NS \
12049 if (hasAxisRange != 0) { \
12050 if (++pos == maxPos) { \
12051 hasNsNodes = 1; \
12052 xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
12053 goto axis_range_end; } \
12054 } else { \
12055 hasNsNodes = 1; \
12056 xmlXPathNodeSetAddNs(seq, \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012057 xpctxt->node, (xmlNsPtr) cur); \
12058 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012059
12060 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
12061 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12062 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12063 const xmlChar *prefix = op->value4;
12064 const xmlChar *name = op->value5;
12065 const xmlChar *URI = NULL;
12066
12067#ifdef DEBUG_STEP
12068 int nbMatches = 0, prevMatches = 0;
12069#endif
12070 int total = 0, hasNsNodes = 0;
12071 /* The popped object holding the context nodes */
12072 xmlXPathObjectPtr obj;
12073 /* The set of context nodes for the node tests */
12074 xmlNodeSetPtr contextSeq;
12075 int contextIdx;
12076 xmlNodePtr contextNode;
12077 /* The context node for a compound traversal */
12078 xmlNodePtr outerContextNode;
12079 /* The final resulting node set wrt to all context nodes */
12080 xmlNodeSetPtr outSeq;
12081 /*
12082 * The temporary resulting node set wrt 1 context node.
12083 * Used to feed predicate evaluation.
12084 */
12085 xmlNodeSetPtr seq;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012086 xmlNodePtr cur;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012087 /* First predicate operator */
12088 xmlXPathStepOpPtr predOp;
12089 int maxPos; /* The requested position() (when a "[n]" predicate) */
12090 int hasPredicateRange, hasAxisRange, pos, size, newSize;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012091 int breakOnFirstHit;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012092
12093 xmlXPathTraversalFunction next = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012094 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12095 xmlXPathNodeSetMergeFunction mergeAndClear;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012096 xmlNodePtr oldContextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012097 xmlXPathContextPtr xpctxt = ctxt->context;
12098
12099
12100 CHECK_TYPE0(XPATH_NODESET);
12101 obj = valuePop(ctxt);
12102 /*
12103 * Setup namespaces.
12104 */
12105 if (prefix != NULL) {
12106 URI = xmlXPathNsLookup(xpctxt, prefix);
12107 if (URI == NULL) {
12108 xmlXPathReleaseObject(xpctxt, obj);
12109 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12110 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012111 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012112 /*
12113 * Setup axis.
12114 *
12115 * MAYBE FUTURE TODO: merging optimizations:
12116 * - If the nodes to be traversed wrt to the initial nodes and
12117 * the current axis cannot overlap, then we could avoid searching
12118 * for duplicates during the merge.
12119 * But the question is how/when to evaluate if they cannot overlap.
12120 * Example: if we know that for two initial nodes, the one is
12121 * not in the ancestor-or-self axis of the other, then we could safely
12122 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12123 * the descendant-or-self axis.
12124 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012125 mergeAndClear = xmlXPathNodeSetMergeAndClear;
12126 switch (axis) {
12127 case AXIS_ANCESTOR:
12128 first = NULL;
12129 next = xmlXPathNextAncestor;
12130 break;
12131 case AXIS_ANCESTOR_OR_SELF:
12132 first = NULL;
12133 next = xmlXPathNextAncestorOrSelf;
12134 break;
12135 case AXIS_ATTRIBUTE:
12136 first = NULL;
12137 last = NULL;
12138 next = xmlXPathNextAttribute;
12139 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12140 break;
12141 case AXIS_CHILD:
12142 last = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012143 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12144 (type == NODE_TYPE_NODE))
12145 {
12146 /*
12147 * Optimization if an element node type is 'element'.
12148 */
12149 next = xmlXPathNextChildElement;
12150 } else
12151 next = xmlXPathNextChild;
12152 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12153 break;
12154 case AXIS_DESCENDANT:
12155 last = NULL;
12156 next = xmlXPathNextDescendant;
12157 break;
12158 case AXIS_DESCENDANT_OR_SELF:
12159 last = NULL;
12160 next = xmlXPathNextDescendantOrSelf;
12161 break;
12162 case AXIS_FOLLOWING:
12163 last = NULL;
12164 next = xmlXPathNextFollowing;
12165 break;
12166 case AXIS_FOLLOWING_SIBLING:
12167 last = NULL;
12168 next = xmlXPathNextFollowingSibling;
12169 break;
12170 case AXIS_NAMESPACE:
12171 first = NULL;
12172 last = NULL;
12173 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12174 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12175 break;
12176 case AXIS_PARENT:
12177 first = NULL;
12178 next = xmlXPathNextParent;
12179 break;
12180 case AXIS_PRECEDING:
12181 first = NULL;
12182 next = xmlXPathNextPrecedingInternal;
12183 break;
12184 case AXIS_PRECEDING_SIBLING:
12185 first = NULL;
12186 next = xmlXPathNextPrecedingSibling;
12187 break;
12188 case AXIS_SELF:
12189 first = NULL;
12190 last = NULL;
12191 next = xmlXPathNextSelf;
12192 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12193 break;
12194 }
12195
12196#ifdef DEBUG_STEP
Daniel Veillard074f37e2008-09-01 13:38:22 +000012197 xmlXPathDebugDumpStepAxis(op,
12198 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012199#endif
12200
12201 if (next == NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000012202 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012203 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012204 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012205 contextSeq = obj->nodesetval;
12206 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12207 xmlXPathReleaseObject(xpctxt, obj);
12208 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12209 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012210 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012211 /*
12212 * Predicate optimization ---------------------------------------------
12213 * If this step has a last predicate, which contains a position(),
12214 * then we'll optimize (although not exactly "position()", but only
12215 * the short-hand form, i.e., "[n]".
12216 *
12217 * Example - expression "/foo[parent::bar][1]":
Daniel Veillard45490ae2008-07-29 09:13:19 +000012218 *
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012219 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12220 * ROOT -- op->ch1
12221 * PREDICATE -- op->ch2 (predOp)
12222 * PREDICATE -- predOp->ch1 = [parent::bar]
12223 * SORT
12224 * COLLECT 'parent' 'name' 'node' bar
12225 * NODE
12226 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12227 *
12228 */
12229 maxPos = 0;
12230 predOp = NULL;
12231 hasPredicateRange = 0;
12232 hasAxisRange = 0;
12233 if (op->ch2 != -1) {
12234 /*
12235 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12236 */
12237 predOp = &ctxt->comp->steps[op->ch2];
12238 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12239 if (predOp->ch1 != -1) {
12240 /*
12241 * Use the next inner predicate operator.
12242 */
12243 predOp = &ctxt->comp->steps[predOp->ch1];
12244 hasPredicateRange = 1;
12245 } else {
12246 /*
12247 * There's no other predicate than the [n] predicate.
12248 */
12249 predOp = NULL;
12250 hasAxisRange = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012251 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012252 }
12253 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012254 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012255 /*
12256 * Axis traversal -----------------------------------------------------
12257 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012258 /*
12259 * 2.3 Node Tests
Daniel Veillard45490ae2008-07-29 09:13:19 +000012260 * - For the attribute axis, the principal node type is attribute.
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012261 * - For the namespace axis, the principal node type is namespace.
12262 * - For other axes, the principal node type is element.
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012263 *
12264 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012265 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012266 * select all element children of the context node
12267 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012268 oldContextNode = xpctxt->node;
12269 addNode = xmlXPathNodeSetAddUnique;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012270 outSeq = NULL;
12271 seq = NULL;
12272 outerContextNode = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012273 contextNode = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012274 contextIdx = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012275
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012276
12277 while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
Nick Wellnhofer62270532012-08-19 19:42:38 +020012278 xpctxt->node = contextSeq->nodeTab[contextIdx++];
Daniel Veillard45490ae2008-07-29 09:13:19 +000012279
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012280 if (seq == NULL) {
12281 seq = xmlXPathNodeSetCreate(NULL);
12282 if (seq == NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012283 total = 0;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012284 goto error;
12285 }
12286 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012287 /*
12288 * Traverse the axis and test the nodes.
12289 */
12290 pos = 0;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012291 cur = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012292 hasNsNodes = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012293 do {
12294 cur = next(ctxt, cur);
12295 if (cur == NULL)
12296 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012297
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012298 /*
12299 * QUESTION TODO: What does the "first" and "last" stuff do?
12300 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012301 if ((first != NULL) && (*first != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012302 if (*first == cur)
12303 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012304 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012305#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012306 (xmlXPathCmpNodesExt(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012307#else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012308 (xmlXPathCmpNodes(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012309#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012310 {
12311 break;
12312 }
12313 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012314 if ((last != NULL) && (*last != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012315 if (*last == cur)
12316 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012317 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012318#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012319 (xmlXPathCmpNodesExt(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012320#else
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012321 (xmlXPathCmpNodes(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012322#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012323 {
12324 break;
12325 }
12326 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012327
12328 total++;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012329
Daniel Veillardf06307e2001-07-03 10:35:50 +000012330#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012331 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12332#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +000012333
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012334 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012335 case NODE_TEST_NONE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012336 total = 0;
12337 STRANGE
12338 goto error;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012339 case NODE_TEST_TYPE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012340 /*
12341 * TODO: Don't we need to use
12342 * xmlXPathNodeSetAddNs() for namespace nodes here?
12343 * Surprisingly, some c14n tests fail, if we do this.
12344 */
12345 if (type == NODE_TYPE_NODE) {
12346 switch (cur->type) {
12347 case XML_DOCUMENT_NODE:
12348 case XML_HTML_DOCUMENT_NODE:
12349#ifdef LIBXML_DOCB_ENABLED
12350 case XML_DOCB_DOCUMENT_NODE:
12351#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +000012352 case XML_ELEMENT_NODE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012353 case XML_ATTRIBUTE_NODE:
12354 case XML_PI_NODE:
12355 case XML_COMMENT_NODE:
12356 case XML_CDATA_SECTION_NODE:
12357 case XML_TEXT_NODE:
12358 case XML_NAMESPACE_DECL:
12359 XP_TEST_HIT
12360 break;
12361 default:
12362 break;
12363 }
12364 } else if (cur->type == type) {
Kasimier T. Buchcik889b7622006-07-03 11:44:13 +000012365 if (type == XML_NAMESPACE_DECL)
12366 XP_TEST_HIT_NS
12367 else
12368 XP_TEST_HIT
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012369 } else if ((type == NODE_TYPE_TEXT) &&
12370 (cur->type == XML_CDATA_SECTION_NODE))
12371 {
12372 XP_TEST_HIT
12373 }
12374 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012375 case NODE_TEST_PI:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012376 if ((cur->type == XML_PI_NODE) &&
12377 ((name == NULL) || xmlStrEqual(name, cur->name)))
12378 {
12379 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012380 }
12381 break;
12382 case NODE_TEST_ALL:
12383 if (axis == AXIS_ATTRIBUTE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012384 if (cur->type == XML_ATTRIBUTE_NODE)
12385 {
12386 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012387 }
12388 } else if (axis == AXIS_NAMESPACE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012389 if (cur->type == XML_NAMESPACE_DECL)
12390 {
12391 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012392 }
12393 } else {
12394 if (cur->type == XML_ELEMENT_NODE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012395 if (prefix == NULL)
12396 {
12397 XP_TEST_HIT
12398
Daniel Veillardf06307e2001-07-03 10:35:50 +000012399 } else if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012400 (xmlStrEqual(URI, cur->ns->href)))
12401 {
12402 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012403 }
12404 }
12405 }
12406 break;
12407 case NODE_TEST_NS:{
12408 TODO;
12409 break;
12410 }
12411 case NODE_TEST_NAME:
Daniel Veillardfe3970e2006-11-23 16:08:30 +000012412 if (axis == AXIS_ATTRIBUTE) {
12413 if (cur->type != XML_ATTRIBUTE_NODE)
12414 break;
12415 } else if (axis == AXIS_NAMESPACE) {
12416 if (cur->type != XML_NAMESPACE_DECL)
12417 break;
12418 } else {
12419 if (cur->type != XML_ELEMENT_NODE)
12420 break;
12421 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012422 switch (cur->type) {
12423 case XML_ELEMENT_NODE:
12424 if (xmlStrEqual(name, cur->name)) {
12425 if (prefix == NULL) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012426 if (cur->ns == NULL)
12427 {
12428 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012429 }
12430 } else {
12431 if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012432 (xmlStrEqual(URI, cur->ns->href)))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012433 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012434 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012435 }
12436 }
12437 }
12438 break;
12439 case XML_ATTRIBUTE_NODE:{
12440 xmlAttrPtr attr = (xmlAttrPtr) cur;
12441
12442 if (xmlStrEqual(name, attr->name)) {
12443 if (prefix == NULL) {
12444 if ((attr->ns == NULL) ||
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012445 (attr->ns->prefix == NULL))
12446 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012447 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012448 }
12449 } else {
12450 if ((attr->ns != NULL) &&
12451 (xmlStrEqual(URI,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012452 attr->ns->href)))
12453 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012454 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012455 }
12456 }
12457 }
12458 break;
12459 }
12460 case XML_NAMESPACE_DECL:
12461 if (cur->type == XML_NAMESPACE_DECL) {
12462 xmlNsPtr ns = (xmlNsPtr) cur;
12463
12464 if ((ns->prefix != NULL) && (name != NULL)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012465 && (xmlStrEqual(ns->prefix, name)))
12466 {
12467 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012468 }
12469 }
12470 break;
12471 default:
12472 break;
12473 }
12474 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012475 } /* switch(test) */
12476 } while (cur != NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012477
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012478 goto apply_predicates;
12479
Daniel Veillard45490ae2008-07-29 09:13:19 +000012480axis_range_end: /* ----------------------------------------------------- */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012481 /*
12482 * We have a "/foo[n]", and position() = n was reached.
12483 * Note that we can have as well "/foo/::parent::foo[1]", so
12484 * a duplicate-aware merge is still needed.
12485 * Merge with the result.
12486 */
12487 if (outSeq == NULL) {
12488 outSeq = seq;
12489 seq = NULL;
12490 } else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012491 outSeq = mergeAndClear(outSeq, seq, 0);
12492 /*
12493 * Break if only a true/false result was requested.
12494 */
12495 if (toBool)
12496 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012497 continue;
12498
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012499first_hit: /* ---------------------------------------------------------- */
12500 /*
12501 * Break if only a true/false result was requested and
12502 * no predicates existed and a node test succeeded.
12503 */
12504 if (outSeq == NULL) {
12505 outSeq = seq;
12506 seq = NULL;
12507 } else
12508 outSeq = mergeAndClear(outSeq, seq, 0);
12509 break;
12510
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012511#ifdef DEBUG_STEP
12512 if (seq != NULL)
12513 nbMatches += seq->nodeNr;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012514#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012515
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012516apply_predicates: /* --------------------------------------------------- */
12517 /*
12518 * Apply predicates.
Daniel Veillard45490ae2008-07-29 09:13:19 +000012519 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012520 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12521 /*
12522 * E.g. when we have a "/foo[some expression][n]".
Daniel Veillard45490ae2008-07-29 09:13:19 +000012523 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012524 /*
12525 * QUESTION TODO: The old predicate evaluation took into
12526 * account location-sets.
12527 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12528 * Do we expect such a set here?
12529 * All what I learned now from the evaluation semantics
12530 * does not indicate that a location-set will be processed
12531 * here, so this looks OK.
Daniel Veillard45490ae2008-07-29 09:13:19 +000012532 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012533 /*
12534 * Iterate over all predicates, starting with the outermost
12535 * predicate.
12536 * TODO: Problem: we cannot execute the inner predicates first
12537 * since we cannot go back *up* the operator tree!
12538 * Options we have:
12539 * 1) Use of recursive functions (like is it currently done
12540 * via xmlXPathCompOpEval())
12541 * 2) Add a predicate evaluation information stack to the
12542 * context struct
12543 * 3) Change the way the operators are linked; we need a
12544 * "parent" field on xmlXPathStepOp
12545 *
12546 * For the moment, I'll try to solve this with a recursive
12547 * function: xmlXPathCompOpEvalPredicate().
Daniel Veillard45490ae2008-07-29 09:13:19 +000012548 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012549 size = seq->nodeNr;
12550 if (hasPredicateRange != 0)
12551 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12552 predOp, seq, size, maxPos, maxPos, hasNsNodes);
12553 else
12554 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12555 predOp, seq, size, hasNsNodes);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012556
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012557 if (ctxt->error != XPATH_EXPRESSION_OK) {
12558 total = 0;
12559 goto error;
12560 }
12561 /*
12562 * Add the filtered set of nodes to the result node set.
12563 */
12564 if (newSize == 0) {
12565 /*
12566 * The predicates filtered all nodes out.
12567 */
12568 xmlXPathNodeSetClear(seq, hasNsNodes);
12569 } else if (seq->nodeNr > 0) {
12570 /*
12571 * Add to result set.
12572 */
12573 if (outSeq == NULL) {
12574 if (size != newSize) {
12575 /*
12576 * We need to merge and clear here, since
12577 * the sequence will contained NULLed entries.
12578 */
12579 outSeq = mergeAndClear(NULL, seq, 1);
12580 } else {
12581 outSeq = seq;
12582 seq = NULL;
12583 }
12584 } else
12585 outSeq = mergeAndClear(outSeq, seq,
12586 (size != newSize) ? 1: 0);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012587 /*
12588 * Break if only a true/false result was requested.
12589 */
12590 if (toBool)
12591 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012592 }
12593 } else if (seq->nodeNr > 0) {
12594 /*
12595 * Add to result set.
12596 */
12597 if (outSeq == NULL) {
12598 outSeq = seq;
12599 seq = NULL;
12600 } else {
12601 outSeq = mergeAndClear(outSeq, seq, 0);
12602 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012603 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012604 }
12605
12606error:
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012607 if ((obj->boolval) && (obj->user != NULL)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012608 /*
12609 * QUESTION TODO: What does this do and why?
12610 * TODO: Do we have to do this also for the "error"
12611 * cleanup further down?
12612 */
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012613 ctxt->value->boolval = 1;
12614 ctxt->value->user = obj->user;
12615 obj->user = NULL;
12616 obj->boolval = 0;
12617 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012618 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012619
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012620 /*
12621 * Ensure we return at least an emtpy set.
12622 */
12623 if (outSeq == NULL) {
12624 if ((seq != NULL) && (seq->nodeNr == 0))
12625 outSeq = seq;
12626 else
12627 outSeq = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +000012628 /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012629 }
12630 if ((seq != NULL) && (seq != outSeq)) {
12631 xmlXPathFreeNodeSet(seq);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012632 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012633 /*
12634 * Hand over the result. Better to push the set also in
12635 * case of errors.
12636 */
12637 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12638 /*
12639 * Reset the context node.
12640 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012641 xpctxt->node = oldContextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012642
12643#ifdef DEBUG_STEP
12644 xmlGenericError(xmlGenericErrorContext,
12645 "\nExamined %d nodes, found %d nodes at that step\n",
12646 total, nbMatches);
12647#endif
12648
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012649 return(total);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012650}
12651
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012652static int
12653xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12654 xmlXPathStepOpPtr op, xmlNodePtr * first);
12655
Daniel Veillardf06307e2001-07-03 10:35:50 +000012656/**
12657 * xmlXPathCompOpEvalFirst:
12658 * @ctxt: the XPath parser context with the compiled expression
12659 * @op: an XPath compiled operation
12660 * @first: the first elem found so far
12661 *
12662 * Evaluate the Precompiled XPath operation searching only the first
12663 * element in document order
12664 *
12665 * Returns the number of examined objects.
12666 */
12667static int
12668xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12669 xmlXPathStepOpPtr op, xmlNodePtr * first)
12670{
12671 int total = 0, cur;
12672 xmlXPathCompExprPtr comp;
12673 xmlXPathObjectPtr arg1, arg2;
12674
Daniel Veillard556c6682001-10-06 09:59:51 +000012675 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012676 comp = ctxt->comp;
12677 switch (op->op) {
12678 case XPATH_OP_END:
12679 return (0);
12680 case XPATH_OP_UNION:
12681 total =
12682 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12683 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012684 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012685 if ((ctxt->value != NULL)
12686 && (ctxt->value->type == XPATH_NODESET)
12687 && (ctxt->value->nodesetval != NULL)
12688 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12689 /*
12690 * limit tree traversing to first node in the result
12691 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012692 /*
12693 * OPTIMIZE TODO: This implicitely sorts
12694 * the result, even if not needed. E.g. if the argument
12695 * of the count() function, no sorting is needed.
12696 * OPTIMIZE TODO: How do we know if the node-list wasn't
12697 * aready sorted?
12698 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012699 if (ctxt->value->nodesetval->nodeNr > 1)
12700 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012701 *first = ctxt->value->nodesetval->nodeTab[0];
12702 }
12703 cur =
12704 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12705 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012706 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012707 CHECK_TYPE0(XPATH_NODESET);
12708 arg2 = valuePop(ctxt);
12709
12710 CHECK_TYPE0(XPATH_NODESET);
12711 arg1 = valuePop(ctxt);
12712
12713 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12714 arg2->nodesetval);
12715 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012716 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012717 /* optimizer */
12718 if (total > cur)
12719 xmlXPathCompSwap(op);
12720 return (total + cur);
12721 case XPATH_OP_ROOT:
12722 xmlXPathRoot(ctxt);
12723 return (0);
12724 case XPATH_OP_NODE:
12725 if (op->ch1 != -1)
12726 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012727 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012728 if (op->ch2 != -1)
12729 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012730 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012731 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12732 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012733 return (total);
12734 case XPATH_OP_RESET:
12735 if (op->ch1 != -1)
12736 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012737 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012738 if (op->ch2 != -1)
12739 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012740 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012741 ctxt->context->node = NULL;
12742 return (total);
12743 case XPATH_OP_COLLECT:{
12744 if (op->ch1 == -1)
12745 return (total);
12746
12747 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012748 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012749
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012750 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012751 return (total);
12752 }
12753 case XPATH_OP_VALUE:
12754 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012755 xmlXPathCacheObjectCopy(ctxt->context,
12756 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012757 return (0);
12758 case XPATH_OP_SORT:
12759 if (op->ch1 != -1)
12760 total +=
12761 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12762 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012763 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012764 if ((ctxt->value != NULL)
12765 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012766 && (ctxt->value->nodesetval != NULL)
12767 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012768 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12769 return (total);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012770#ifdef XP_OPTIMIZED_FILTER_FIRST
12771 case XPATH_OP_FILTER:
Marius Wachtler2ddecc22010-10-12 09:09:07 +020012772 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012773 return (total);
12774#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000012775 default:
12776 return (xmlXPathCompOpEval(ctxt, op));
12777 }
12778}
12779
12780/**
12781 * xmlXPathCompOpEvalLast:
12782 * @ctxt: the XPath parser context with the compiled expression
12783 * @op: an XPath compiled operation
12784 * @last: the last elem found so far
12785 *
12786 * Evaluate the Precompiled XPath operation searching only the last
12787 * element in document order
12788 *
William M. Brack08171912003-12-29 02:52:11 +000012789 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000012790 */
12791static int
12792xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12793 xmlNodePtr * last)
12794{
12795 int total = 0, cur;
12796 xmlXPathCompExprPtr comp;
12797 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +000012798 xmlNodePtr bak;
12799 xmlDocPtr bakd;
12800 int pp;
12801 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012802
Daniel Veillard556c6682001-10-06 09:59:51 +000012803 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012804 comp = ctxt->comp;
12805 switch (op->op) {
12806 case XPATH_OP_END:
12807 return (0);
12808 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +000012809 bakd = ctxt->context->doc;
12810 bak = ctxt->context->node;
12811 pp = ctxt->context->proximityPosition;
12812 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012813 total =
12814 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012815 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012816 if ((ctxt->value != NULL)
12817 && (ctxt->value->type == XPATH_NODESET)
12818 && (ctxt->value->nodesetval != NULL)
12819 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12820 /*
12821 * limit tree traversing to first node in the result
12822 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012823 if (ctxt->value->nodesetval->nodeNr > 1)
12824 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012825 *last =
12826 ctxt->value->nodesetval->nodeTab[ctxt->value->
12827 nodesetval->nodeNr -
12828 1];
12829 }
William M. Brackce4fc562004-01-22 02:47:18 +000012830 ctxt->context->doc = bakd;
12831 ctxt->context->node = bak;
12832 ctxt->context->proximityPosition = pp;
12833 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012834 cur =
12835 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012836 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012837 if ((ctxt->value != NULL)
12838 && (ctxt->value->type == XPATH_NODESET)
12839 && (ctxt->value->nodesetval != NULL)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012840 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012841 }
12842 CHECK_TYPE0(XPATH_NODESET);
12843 arg2 = valuePop(ctxt);
12844
12845 CHECK_TYPE0(XPATH_NODESET);
12846 arg1 = valuePop(ctxt);
12847
12848 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12849 arg2->nodesetval);
12850 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012851 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012852 /* optimizer */
12853 if (total > cur)
12854 xmlXPathCompSwap(op);
12855 return (total + cur);
12856 case XPATH_OP_ROOT:
12857 xmlXPathRoot(ctxt);
12858 return (0);
12859 case XPATH_OP_NODE:
12860 if (op->ch1 != -1)
12861 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012862 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012863 if (op->ch2 != -1)
12864 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012865 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012866 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12867 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012868 return (total);
12869 case XPATH_OP_RESET:
12870 if (op->ch1 != -1)
12871 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012872 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012873 if (op->ch2 != -1)
12874 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012875 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012876 ctxt->context->node = NULL;
12877 return (total);
12878 case XPATH_OP_COLLECT:{
12879 if (op->ch1 == -1)
12880 return (0);
12881
12882 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012883 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012884
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012885 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012886 return (total);
12887 }
12888 case XPATH_OP_VALUE:
12889 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012890 xmlXPathCacheObjectCopy(ctxt->context,
12891 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012892 return (0);
12893 case XPATH_OP_SORT:
12894 if (op->ch1 != -1)
12895 total +=
12896 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12897 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012898 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012899 if ((ctxt->value != NULL)
12900 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012901 && (ctxt->value->nodesetval != NULL)
12902 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012903 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12904 return (total);
12905 default:
12906 return (xmlXPathCompOpEval(ctxt, op));
12907 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012908}
12909
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012910#ifdef XP_OPTIMIZED_FILTER_FIRST
12911static int
12912xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12913 xmlXPathStepOpPtr op, xmlNodePtr * first)
12914{
12915 int total = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012916 xmlXPathCompExprPtr comp;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012917 xmlXPathObjectPtr res;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012918 xmlXPathObjectPtr obj;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012919 xmlNodeSetPtr oldset;
12920 xmlNodePtr oldnode;
12921 xmlDocPtr oldDoc;
12922 int i;
12923
12924 CHECK_ERROR0;
12925 comp = ctxt->comp;
12926 /*
12927 * Optimization for ()[last()] selection i.e. the last elem
12928 */
12929 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12930 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12931 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12932 int f = comp->steps[op->ch2].ch1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012933
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012934 if ((f != -1) &&
12935 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12936 (comp->steps[f].value5 == NULL) &&
12937 (comp->steps[f].value == 0) &&
12938 (comp->steps[f].value4 != NULL) &&
12939 (xmlStrEqual
12940 (comp->steps[f].value4, BAD_CAST "last"))) {
12941 xmlNodePtr last = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012942
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012943 total +=
12944 xmlXPathCompOpEvalLast(ctxt,
12945 &comp->steps[op->ch1],
12946 &last);
12947 CHECK_ERROR0;
12948 /*
12949 * The nodeset should be in document order,
12950 * Keep only the last value
12951 */
12952 if ((ctxt->value != NULL) &&
12953 (ctxt->value->type == XPATH_NODESET) &&
12954 (ctxt->value->nodesetval != NULL) &&
12955 (ctxt->value->nodesetval->nodeTab != NULL) &&
12956 (ctxt->value->nodesetval->nodeNr > 1)) {
12957 ctxt->value->nodesetval->nodeTab[0] =
12958 ctxt->value->nodesetval->nodeTab[ctxt->
12959 value->
12960 nodesetval->
12961 nodeNr -
12962 1];
12963 ctxt->value->nodesetval->nodeNr = 1;
12964 *first = *(ctxt->value->nodesetval->nodeTab);
12965 }
12966 return (total);
12967 }
12968 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012969
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012970 if (op->ch1 != -1)
12971 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12972 CHECK_ERROR0;
12973 if (op->ch2 == -1)
12974 return (total);
12975 if (ctxt->value == NULL)
12976 return (total);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012977
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012978#ifdef LIBXML_XPTR_ENABLED
12979 oldnode = ctxt->context->node;
12980 /*
12981 * Hum are we filtering the result of an XPointer expression
12982 */
12983 if (ctxt->value->type == XPATH_LOCATIONSET) {
12984 xmlXPathObjectPtr tmp = NULL;
12985 xmlLocationSetPtr newlocset = NULL;
12986 xmlLocationSetPtr oldlocset;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012987
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012988 /*
12989 * Extract the old locset, and then evaluate the result of the
12990 * expression for all the element in the locset. use it to grow
12991 * up a new locset.
12992 */
12993 CHECK_TYPE0(XPATH_LOCATIONSET);
12994 obj = valuePop(ctxt);
12995 oldlocset = obj->user;
12996 ctxt->context->node = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012997
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012998 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12999 ctxt->context->contextSize = 0;
13000 ctxt->context->proximityPosition = 0;
13001 if (op->ch2 != -1)
13002 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13003 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013004 if (res != NULL) {
13005 xmlXPathReleaseObject(ctxt->context, res);
13006 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013007 valuePush(ctxt, obj);
13008 CHECK_ERROR0;
13009 return (total);
13010 }
13011 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013012
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013013 for (i = 0; i < oldlocset->locNr; i++) {
13014 /*
13015 * Run the evaluation with a node list made of a
13016 * single item in the nodelocset.
13017 */
13018 ctxt->context->node = oldlocset->locTab[i]->user;
13019 ctxt->context->contextSize = oldlocset->locNr;
13020 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013021 if (tmp == NULL) {
13022 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13023 ctxt->context->node);
13024 } else {
13025 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13026 ctxt->context->node);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013027 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013028 valuePush(ctxt, tmp);
13029 if (op->ch2 != -1)
13030 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13031 if (ctxt->error != XPATH_EXPRESSION_OK) {
13032 xmlXPathFreeObject(obj);
13033 return(0);
13034 }
13035 /*
13036 * The result of the evaluation need to be tested to
13037 * decided whether the filter succeeded or not
13038 */
13039 res = valuePop(ctxt);
13040 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13041 xmlXPtrLocationSetAdd(newlocset,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013042 xmlXPathCacheObjectCopy(ctxt->context,
13043 oldlocset->locTab[i]));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013044 }
13045 /*
13046 * Cleanup
13047 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013048 if (res != NULL) {
13049 xmlXPathReleaseObject(ctxt->context, res);
13050 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013051 if (ctxt->value == tmp) {
13052 valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013053 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013054 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013055 * REVISIT TODO: Don't create a temporary nodeset
13056 * for everly iteration.
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013057 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013058 /* OLD: xmlXPathFreeObject(res); */
13059 } else
Daniel Veillard45490ae2008-07-29 09:13:19 +000013060 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013061 ctxt->context->node = NULL;
13062 /*
13063 * Only put the first node in the result, then leave.
13064 */
13065 if (newlocset->locNr > 0) {
13066 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
13067 break;
13068 }
13069 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013070 if (tmp != NULL) {
13071 xmlXPathReleaseObject(ctxt->context, tmp);
13072 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013073 /*
13074 * The result is used as the new evaluation locset.
13075 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013076 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013077 ctxt->context->node = NULL;
13078 ctxt->context->contextSize = -1;
13079 ctxt->context->proximityPosition = -1;
13080 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13081 ctxt->context->node = oldnode;
13082 return (total);
13083 }
13084#endif /* LIBXML_XPTR_ENABLED */
Daniel Veillard45490ae2008-07-29 09:13:19 +000013085
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013086 /*
13087 * Extract the old set, and then evaluate the result of the
13088 * expression for all the element in the set. use it to grow
13089 * up a new set.
13090 */
13091 CHECK_TYPE0(XPATH_NODESET);
13092 obj = valuePop(ctxt);
13093 oldset = obj->nodesetval;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013094
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013095 oldnode = ctxt->context->node;
13096 oldDoc = ctxt->context->doc;
13097 ctxt->context->node = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013098
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013099 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13100 ctxt->context->contextSize = 0;
13101 ctxt->context->proximityPosition = 0;
13102 /* QUESTION TODO: Why was this code commented out?
13103 if (op->ch2 != -1)
13104 total +=
13105 xmlXPathCompOpEval(ctxt,
13106 &comp->steps[op->ch2]);
13107 CHECK_ERROR0;
13108 res = valuePop(ctxt);
13109 if (res != NULL)
13110 xmlXPathFreeObject(res);
13111 */
13112 valuePush(ctxt, obj);
13113 ctxt->context->node = oldnode;
13114 CHECK_ERROR0;
13115 } else {
13116 xmlNodeSetPtr newset;
13117 xmlXPathObjectPtr tmp = NULL;
13118 /*
13119 * Initialize the new set.
13120 * Also set the xpath document in case things like
13121 * key() evaluation are attempted on the predicate
Daniel Veillard45490ae2008-07-29 09:13:19 +000013122 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013123 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +000013124 /* XXX what if xmlXPathNodeSetCreate returned NULL? */
Daniel Veillard45490ae2008-07-29 09:13:19 +000013125
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013126 for (i = 0; i < oldset->nodeNr; i++) {
13127 /*
13128 * Run the evaluation with a node list made of
13129 * a single item in the nodeset.
13130 */
13131 ctxt->context->node = oldset->nodeTab[i];
13132 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13133 (oldset->nodeTab[i]->doc != NULL))
13134 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013135 if (tmp == NULL) {
13136 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13137 ctxt->context->node);
13138 } else {
13139 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13140 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013141 }
13142 valuePush(ctxt, tmp);
13143 ctxt->context->contextSize = oldset->nodeNr;
13144 ctxt->context->proximityPosition = i + 1;
13145 if (op->ch2 != -1)
13146 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13147 if (ctxt->error != XPATH_EXPRESSION_OK) {
13148 xmlXPathFreeNodeSet(newset);
13149 xmlXPathFreeObject(obj);
13150 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013151 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013152 /*
13153 * The result of the evaluation needs to be tested to
13154 * decide whether the filter succeeded or not
13155 */
13156 res = valuePop(ctxt);
13157 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13158 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013159 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013160 /*
13161 * Cleanup
13162 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013163 if (res != NULL) {
13164 xmlXPathReleaseObject(ctxt->context, res);
13165 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013166 if (ctxt->value == tmp) {
13167 valuePop(ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013168 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013169 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013170 * in order to avoid massive recreation inside this
13171 * loop.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013172 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000013173 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013174 } else
13175 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013176 ctxt->context->node = NULL;
13177 /*
13178 * Only put the first node in the result, then leave.
13179 */
13180 if (newset->nodeNr > 0) {
13181 *first = *(newset->nodeTab);
13182 break;
13183 }
13184 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013185 if (tmp != NULL) {
13186 xmlXPathReleaseObject(ctxt->context, tmp);
13187 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013188 /*
13189 * The result is used as the new evaluation set.
13190 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013191 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013192 ctxt->context->node = NULL;
13193 ctxt->context->contextSize = -1;
13194 ctxt->context->proximityPosition = -1;
13195 /* may want to move this past the '}' later */
13196 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013197 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013198 }
13199 ctxt->context->node = oldnode;
13200 return(total);
13201}
13202#endif /* XP_OPTIMIZED_FILTER_FIRST */
13203
Owen Taylor3473f882001-02-23 17:55:21 +000013204/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013205 * xmlXPathCompOpEval:
13206 * @ctxt: the XPath parser context with the compiled expression
13207 * @op: an XPath compiled operation
13208 *
13209 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000013210 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013211 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013212static int
13213xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13214{
13215 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013216 int equal, ret;
13217 xmlXPathCompExprPtr comp;
13218 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013219 xmlNodePtr bak;
13220 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000013221 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000013222 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013223
Daniel Veillard556c6682001-10-06 09:59:51 +000013224 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013225 comp = ctxt->comp;
13226 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013227 case XPATH_OP_END:
13228 return (0);
13229 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013230 bakd = ctxt->context->doc;
13231 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013232 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013233 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013234 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013235 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013236 xmlXPathBooleanFunction(ctxt, 1);
13237 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13238 return (total);
13239 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013240 ctxt->context->doc = bakd;
13241 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013242 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013243 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013244 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013245 if (ctxt->error) {
13246 xmlXPathFreeObject(arg2);
13247 return(0);
13248 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013249 xmlXPathBooleanFunction(ctxt, 1);
13250 arg1 = valuePop(ctxt);
13251 arg1->boolval &= arg2->boolval;
13252 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013253 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013254 return (total);
13255 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013256 bakd = ctxt->context->doc;
13257 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013258 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013259 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013260 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013261 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013262 xmlXPathBooleanFunction(ctxt, 1);
13263 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13264 return (total);
13265 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013266 ctxt->context->doc = bakd;
13267 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013268 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013269 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013270 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013271 if (ctxt->error) {
13272 xmlXPathFreeObject(arg2);
13273 return(0);
13274 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013275 xmlXPathBooleanFunction(ctxt, 1);
13276 arg1 = valuePop(ctxt);
13277 arg1->boolval |= arg2->boolval;
13278 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013279 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013280 return (total);
13281 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013282 bakd = ctxt->context->doc;
13283 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013284 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013285 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013286 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013287 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013288 ctxt->context->doc = bakd;
13289 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013290 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013291 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013292 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013293 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000013294 if (op->value)
Daniel Veillard45490ae2008-07-29 09:13:19 +000013295 equal = xmlXPathEqualValues(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +000013296 else
13297 equal = xmlXPathNotEqualValues(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013298 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013299 return (total);
13300 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013301 bakd = ctxt->context->doc;
13302 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013303 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013304 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013305 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013306 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013307 ctxt->context->doc = bakd;
13308 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013309 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013310 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013311 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013312 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013313 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013314 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013315 return (total);
13316 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013317 bakd = ctxt->context->doc;
13318 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013319 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013320 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013321 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013322 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013323 if (op->ch2 != -1) {
13324 ctxt->context->doc = bakd;
13325 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013326 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013327 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013328 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013329 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013330 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013331 if (op->value == 0)
13332 xmlXPathSubValues(ctxt);
13333 else if (op->value == 1)
13334 xmlXPathAddValues(ctxt);
13335 else if (op->value == 2)
13336 xmlXPathValueFlipSign(ctxt);
13337 else if (op->value == 3) {
13338 CAST_TO_NUMBER;
13339 CHECK_TYPE0(XPATH_NUMBER);
13340 }
13341 return (total);
13342 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013343 bakd = ctxt->context->doc;
13344 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013345 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013346 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013347 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013348 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013349 ctxt->context->doc = bakd;
13350 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013351 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013352 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013353 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013354 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013355 if (op->value == 0)
13356 xmlXPathMultValues(ctxt);
13357 else if (op->value == 1)
13358 xmlXPathDivValues(ctxt);
13359 else if (op->value == 2)
13360 xmlXPathModValues(ctxt);
13361 return (total);
13362 case XPATH_OP_UNION:
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 ctxt->context->doc = bakd;
13370 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013371 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013372 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013373 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013374 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013375 CHECK_TYPE0(XPATH_NODESET);
13376 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013377
Daniel Veillardf06307e2001-07-03 10:35:50 +000013378 CHECK_TYPE0(XPATH_NODESET);
13379 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013380
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013381 if ((arg1->nodesetval == NULL) ||
13382 ((arg2->nodesetval != NULL) &&
13383 (arg2->nodesetval->nodeNr != 0)))
13384 {
13385 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13386 arg2->nodesetval);
13387 }
13388
Daniel Veillardf06307e2001-07-03 10:35:50 +000013389 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013390 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013391 return (total);
13392 case XPATH_OP_ROOT:
13393 xmlXPathRoot(ctxt);
13394 return (total);
13395 case XPATH_OP_NODE:
13396 if (op->ch1 != -1)
13397 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013398 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013399 if (op->ch2 != -1)
13400 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013401 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013402 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13403 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013404 return (total);
13405 case XPATH_OP_RESET:
13406 if (op->ch1 != -1)
13407 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013408 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013409 if (op->ch2 != -1)
13410 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013411 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013412 ctxt->context->node = NULL;
13413 return (total);
13414 case XPATH_OP_COLLECT:{
13415 if (op->ch1 == -1)
13416 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000013417
Daniel Veillardf06307e2001-07-03 10:35:50 +000013418 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013419 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013420
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013421 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013422 return (total);
13423 }
13424 case XPATH_OP_VALUE:
13425 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013426 xmlXPathCacheObjectCopy(ctxt->context,
13427 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013428 return (total);
13429 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000013430 xmlXPathObjectPtr val;
13431
Daniel Veillardf06307e2001-07-03 10:35:50 +000013432 if (op->ch1 != -1)
13433 total +=
13434 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013435 if (op->value5 == NULL) {
13436 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13437 if (val == NULL) {
13438 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13439 return(0);
13440 }
13441 valuePush(ctxt, val);
13442 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013443 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013444
Daniel Veillardf06307e2001-07-03 10:35:50 +000013445 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13446 if (URI == NULL) {
13447 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013448 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13449 (char *) op->value4, (char *)op->value5);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080013450 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013451 return (total);
13452 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013453 val = xmlXPathVariableLookupNS(ctxt->context,
13454 op->value4, URI);
13455 if (val == NULL) {
13456 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13457 return(0);
13458 }
13459 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013460 }
13461 return (total);
13462 }
13463 case XPATH_OP_FUNCTION:{
13464 xmlXPathFunction func;
13465 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000013466 int i;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013467 int frame;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013468
Daniel Veillardf5048b32011-08-18 17:10:13 +080013469 frame = xmlXPathSetFrame(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013470 if (op->ch1 != -1)
13471 total +=
13472 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013473 if (ctxt->valueNr < op->value) {
13474 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013475 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013476 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013477 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard556c6682001-10-06 09:59:51 +000013478 return (total);
13479 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080013480 for (i = 0; i < op->value; i++) {
Daniel Veillard556c6682001-10-06 09:59:51 +000013481 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13482 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013483 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013484 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013485 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard556c6682001-10-06 09:59:51 +000013486 return (total);
13487 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080013488 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013489 if (op->cache != NULL)
William M. Brackad0e67c2004-12-01 14:35:10 +000013490 XML_CAST_FPTR(func) = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013491 else {
13492 const xmlChar *URI = NULL;
13493
13494 if (op->value5 == NULL)
13495 func =
13496 xmlXPathFunctionLookup(ctxt->context,
13497 op->value4);
13498 else {
13499 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13500 if (URI == NULL) {
13501 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013502 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13503 (char *)op->value4, (char *)op->value5);
Daniel Veillardf5048b32011-08-18 17:10:13 +080013504 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080013505 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013506 return (total);
13507 }
13508 func = xmlXPathFunctionLookupNS(ctxt->context,
13509 op->value4, URI);
13510 }
13511 if (func == NULL) {
13512 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013513 "xmlXPathCompOpEval: function %s not found\n",
13514 (char *)op->value4);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013515 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013516 }
William M. Brackad0e67c2004-12-01 14:35:10 +000013517 op->cache = XML_CAST_FPTR(func);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013518 op->cacheURI = (void *) URI;
13519 }
13520 oldFunc = ctxt->context->function;
13521 oldFuncURI = ctxt->context->functionURI;
13522 ctxt->context->function = op->value4;
13523 ctxt->context->functionURI = op->cacheURI;
13524 func(ctxt, op->value);
13525 ctxt->context->function = oldFunc;
13526 ctxt->context->functionURI = oldFuncURI;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013527 xmlXPathPopFrame(ctxt, frame);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013528 return (total);
13529 }
13530 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000013531 bakd = ctxt->context->doc;
13532 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000013533 pp = ctxt->context->proximityPosition;
13534 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013535 if (op->ch1 != -1)
13536 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
William M. Brack645a9242004-11-09 12:20:42 +000013537 ctxt->context->contextSize = cs;
13538 ctxt->context->proximityPosition = pp;
Daniel Veillard088bf112002-05-14 11:03:59 +000013539 ctxt->context->node = bak;
William M. Brack645a9242004-11-09 12:20:42 +000013540 ctxt->context->doc = bakd;
Daniel Veillard556c6682001-10-06 09:59:51 +000013541 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000013542 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013543 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000013544 ctxt->context->doc = bakd;
13545 ctxt->context->node = bak;
13546 CHECK_ERROR0;
13547 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013548 return (total);
13549 case XPATH_OP_PREDICATE:
13550 case XPATH_OP_FILTER:{
13551 xmlXPathObjectPtr res;
13552 xmlXPathObjectPtr obj, tmp;
13553 xmlNodeSetPtr newset = NULL;
13554 xmlNodeSetPtr oldset;
13555 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000013556 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013557 int i;
13558
13559 /*
13560 * Optimization for ()[1] selection i.e. the first elem
13561 */
13562 if ((op->ch1 != -1) && (op->ch2 != -1) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013563#ifdef XP_OPTIMIZED_FILTER_FIRST
13564 /*
13565 * FILTER TODO: Can we assume that the inner processing
13566 * will result in an ordered list if we have an
13567 * XPATH_OP_FILTER?
13568 * What about an additional field or flag on
13569 * xmlXPathObject like @sorted ? This way we wouln'd need
13570 * to assume anything, so it would be more robust and
13571 * easier to optimize.
13572 */
13573 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13574 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13575#else
13576 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13577#endif
13578 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013579 xmlXPathObjectPtr val;
13580
13581 val = comp->steps[op->ch2].value4;
13582 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13583 (val->floatval == 1.0)) {
13584 xmlNodePtr first = NULL;
13585
13586 total +=
13587 xmlXPathCompOpEvalFirst(ctxt,
13588 &comp->steps[op->ch1],
13589 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000013590 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013591 /*
13592 * The nodeset should be in document order,
13593 * Keep only the first value
13594 */
13595 if ((ctxt->value != NULL) &&
13596 (ctxt->value->type == XPATH_NODESET) &&
13597 (ctxt->value->nodesetval != NULL) &&
13598 (ctxt->value->nodesetval->nodeNr > 1))
13599 ctxt->value->nodesetval->nodeNr = 1;
13600 return (total);
13601 }
13602 }
13603 /*
13604 * Optimization for ()[last()] selection i.e. the last elem
13605 */
13606 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13607 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13608 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13609 int f = comp->steps[op->ch2].ch1;
13610
13611 if ((f != -1) &&
13612 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13613 (comp->steps[f].value5 == NULL) &&
13614 (comp->steps[f].value == 0) &&
13615 (comp->steps[f].value4 != NULL) &&
13616 (xmlStrEqual
13617 (comp->steps[f].value4, BAD_CAST "last"))) {
13618 xmlNodePtr last = NULL;
13619
13620 total +=
13621 xmlXPathCompOpEvalLast(ctxt,
13622 &comp->steps[op->ch1],
13623 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000013624 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013625 /*
13626 * The nodeset should be in document order,
13627 * Keep only the last value
13628 */
13629 if ((ctxt->value != NULL) &&
13630 (ctxt->value->type == XPATH_NODESET) &&
13631 (ctxt->value->nodesetval != NULL) &&
13632 (ctxt->value->nodesetval->nodeTab != NULL) &&
13633 (ctxt->value->nodesetval->nodeNr > 1)) {
13634 ctxt->value->nodesetval->nodeTab[0] =
13635 ctxt->value->nodesetval->nodeTab[ctxt->
13636 value->
13637 nodesetval->
13638 nodeNr -
13639 1];
13640 ctxt->value->nodesetval->nodeNr = 1;
13641 }
13642 return (total);
13643 }
13644 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013645 /*
13646 * Process inner predicates first.
13647 * Example "index[parent::book][1]":
13648 * ...
13649 * PREDICATE <-- we are here "[1]"
13650 * PREDICATE <-- process "[parent::book]" first
13651 * SORT
13652 * COLLECT 'parent' 'name' 'node' book
13653 * NODE
13654 * ELEM Object is a number : 1
13655 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013656 if (op->ch1 != -1)
13657 total +=
13658 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013659 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013660 if (op->ch2 == -1)
13661 return (total);
13662 if (ctxt->value == NULL)
13663 return (total);
13664
13665 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013666
13667#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013668 /*
13669 * Hum are we filtering the result of an XPointer expression
13670 */
13671 if (ctxt->value->type == XPATH_LOCATIONSET) {
13672 xmlLocationSetPtr newlocset = NULL;
13673 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013674
Daniel Veillardf06307e2001-07-03 10:35:50 +000013675 /*
13676 * Extract the old locset, and then evaluate the result of the
13677 * expression for all the element in the locset. use it to grow
13678 * up a new locset.
13679 */
13680 CHECK_TYPE0(XPATH_LOCATIONSET);
13681 obj = valuePop(ctxt);
13682 oldlocset = obj->user;
13683 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013684
Daniel Veillardf06307e2001-07-03 10:35:50 +000013685 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13686 ctxt->context->contextSize = 0;
13687 ctxt->context->proximityPosition = 0;
13688 if (op->ch2 != -1)
13689 total +=
13690 xmlXPathCompOpEval(ctxt,
13691 &comp->steps[op->ch2]);
13692 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013693 if (res != NULL) {
13694 xmlXPathReleaseObject(ctxt->context, res);
13695 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013696 valuePush(ctxt, obj);
13697 CHECK_ERROR0;
13698 return (total);
13699 }
13700 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013701
Daniel Veillardf06307e2001-07-03 10:35:50 +000013702 for (i = 0; i < oldlocset->locNr; i++) {
13703 /*
13704 * Run the evaluation with a node list made of a
13705 * single item in the nodelocset.
13706 */
13707 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013708 ctxt->context->contextSize = oldlocset->locNr;
13709 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013710 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13711 ctxt->context->node);
William M. Brackf7eb7942003-12-31 07:59:17 +000013712 valuePush(ctxt, tmp);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013713
Daniel Veillardf06307e2001-07-03 10:35:50 +000013714 if (op->ch2 != -1)
13715 total +=
13716 xmlXPathCompOpEval(ctxt,
13717 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013718 if (ctxt->error != XPATH_EXPRESSION_OK) {
13719 xmlXPathFreeObject(obj);
13720 return(0);
13721 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013722
Daniel Veillardf06307e2001-07-03 10:35:50 +000013723 /*
13724 * The result of the evaluation need to be tested to
13725 * decided whether the filter succeeded or not
13726 */
13727 res = valuePop(ctxt);
13728 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13729 xmlXPtrLocationSetAdd(newlocset,
13730 xmlXPathObjectCopy
13731 (oldlocset->locTab[i]));
13732 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013733
Daniel Veillardf06307e2001-07-03 10:35:50 +000013734 /*
13735 * Cleanup
13736 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013737 if (res != NULL) {
13738 xmlXPathReleaseObject(ctxt->context, res);
13739 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013740 if (ctxt->value == tmp) {
13741 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013742 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013743 }
13744
13745 ctxt->context->node = NULL;
13746 }
13747
13748 /*
13749 * The result is used as the new evaluation locset.
13750 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013751 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013752 ctxt->context->node = NULL;
13753 ctxt->context->contextSize = -1;
13754 ctxt->context->proximityPosition = -1;
13755 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13756 ctxt->context->node = oldnode;
13757 return (total);
13758 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013759#endif /* LIBXML_XPTR_ENABLED */
13760
Daniel Veillardf06307e2001-07-03 10:35:50 +000013761 /*
13762 * Extract the old set, and then evaluate the result of the
13763 * expression for all the element in the set. use it to grow
13764 * up a new set.
13765 */
13766 CHECK_TYPE0(XPATH_NODESET);
13767 obj = valuePop(ctxt);
13768 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000013769
Daniel Veillardf06307e2001-07-03 10:35:50 +000013770 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000013771 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013772 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013773
Daniel Veillardf06307e2001-07-03 10:35:50 +000013774 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13775 ctxt->context->contextSize = 0;
13776 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000013777/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000013778 if (op->ch2 != -1)
13779 total +=
13780 xmlXPathCompOpEval(ctxt,
13781 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013782 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013783 res = valuePop(ctxt);
13784 if (res != NULL)
13785 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000013786*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000013787 valuePush(ctxt, obj);
13788 ctxt->context->node = oldnode;
13789 CHECK_ERROR0;
13790 } else {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013791 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013792 /*
13793 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000013794 * Also set the xpath document in case things like
13795 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000013796 */
13797 newset = xmlXPathNodeSetCreate(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013798 /*
13799 * SPEC XPath 1.0:
13800 * "For each node in the node-set to be filtered, the
13801 * PredicateExpr is evaluated with that node as the
13802 * context node, with the number of nodes in the
13803 * node-set as the context size, and with the proximity
13804 * position of the node in the node-set with respect to
13805 * the axis as the context position;"
13806 * @oldset is the node-set" to be filtered.
13807 *
13808 * SPEC XPath 1.0:
13809 * "only predicates change the context position and
13810 * context size (see [2.4 Predicates])."
13811 * Example:
13812 * node-set context pos
13813 * nA 1
13814 * nB 2
13815 * nC 3
13816 * After applying predicate [position() > 1] :
13817 * node-set context pos
13818 * nB 1
13819 * nC 2
13820 *
13821 * removed the first node in the node-set, then
Daniel Veillard45490ae2008-07-29 09:13:19 +000013822 * the context position of the
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013823 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013824 for (i = 0; i < oldset->nodeNr; i++) {
13825 /*
13826 * Run the evaluation with a node list made of
13827 * a single item in the nodeset.
13828 */
13829 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000013830 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13831 (oldset->nodeTab[i]->doc != NULL))
13832 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013833 if (tmp == NULL) {
13834 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13835 ctxt->context->node);
13836 } else {
13837 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13838 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013839 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013840 valuePush(ctxt, tmp);
13841 ctxt->context->contextSize = oldset->nodeNr;
13842 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013843 /*
13844 * Evaluate the predicate against the context node.
13845 * Can/should we optimize position() predicates
13846 * here (e.g. "[1]")?
13847 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013848 if (op->ch2 != -1)
13849 total +=
13850 xmlXPathCompOpEval(ctxt,
13851 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013852 if (ctxt->error != XPATH_EXPRESSION_OK) {
13853 xmlXPathFreeNodeSet(newset);
13854 xmlXPathFreeObject(obj);
13855 return(0);
13856 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013857
Daniel Veillardf06307e2001-07-03 10:35:50 +000013858 /*
William M. Brack08171912003-12-29 02:52:11 +000013859 * The result of the evaluation needs to be tested to
13860 * decide whether the filter succeeded or not
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013861 */
13862 /*
13863 * OPTIMIZE TODO: Can we use
13864 * xmlXPathNodeSetAdd*Unique()* instead?
13865 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013866 res = valuePop(ctxt);
13867 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13868 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13869 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013870
Daniel Veillardf06307e2001-07-03 10:35:50 +000013871 /*
13872 * Cleanup
13873 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013874 if (res != NULL) {
13875 xmlXPathReleaseObject(ctxt->context, res);
13876 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013877 if (ctxt->value == tmp) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013878 valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013879 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013880 /*
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013881 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013882 * in order to avoid massive recreation inside this
13883 * loop.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013884 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013885 } else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013886 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013887 ctxt->context->node = NULL;
13888 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013889 if (tmp != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013890 xmlXPathReleaseObject(ctxt->context, tmp);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013891 /*
13892 * The result is used as the new evaluation set.
13893 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013894 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013895 ctxt->context->node = NULL;
13896 ctxt->context->contextSize = -1;
13897 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000013898 /* may want to move this past the '}' later */
13899 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013900 valuePush(ctxt,
13901 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013902 }
13903 ctxt->context->node = oldnode;
13904 return (total);
13905 }
13906 case XPATH_OP_SORT:
13907 if (op->ch1 != -1)
13908 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013909 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013910 if ((ctxt->value != NULL) &&
13911 (ctxt->value->type == XPATH_NODESET) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013912 (ctxt->value->nodesetval != NULL) &&
13913 (ctxt->value->nodesetval->nodeNr > 1))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013914 {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013915 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013916 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013917 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013918#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013919 case XPATH_OP_RANGETO:{
13920 xmlXPathObjectPtr range;
13921 xmlXPathObjectPtr res, obj;
13922 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000013923 xmlLocationSetPtr newlocset = NULL;
13924 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013925 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000013926 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013927
Daniel Veillardf06307e2001-07-03 10:35:50 +000013928 if (op->ch1 != -1)
13929 total +=
13930 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13931 if (op->ch2 == -1)
13932 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013933
William M. Brack08171912003-12-29 02:52:11 +000013934 if (ctxt->value->type == XPATH_LOCATIONSET) {
13935 /*
13936 * Extract the old locset, and then evaluate the result of the
13937 * expression for all the element in the locset. use it to grow
13938 * up a new locset.
13939 */
13940 CHECK_TYPE0(XPATH_LOCATIONSET);
13941 obj = valuePop(ctxt);
13942 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013943
William M. Brack08171912003-12-29 02:52:11 +000013944 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000013945 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000013946 ctxt->context->contextSize = 0;
13947 ctxt->context->proximityPosition = 0;
13948 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13949 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013950 if (res != NULL) {
13951 xmlXPathReleaseObject(ctxt->context, res);
13952 }
William M. Brack08171912003-12-29 02:52:11 +000013953 valuePush(ctxt, obj);
13954 CHECK_ERROR0;
13955 return (total);
13956 }
13957 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013958
William M. Brack08171912003-12-29 02:52:11 +000013959 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013960 /*
William M. Brack08171912003-12-29 02:52:11 +000013961 * Run the evaluation with a node list made of a
13962 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000013963 */
William M. Brackf7eb7942003-12-31 07:59:17 +000013964 ctxt->context->node = oldlocset->locTab[i]->user;
13965 ctxt->context->contextSize = oldlocset->locNr;
13966 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013967 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13968 ctxt->context->node);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013969 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013970
Daniel Veillardf06307e2001-07-03 10:35:50 +000013971 if (op->ch2 != -1)
13972 total +=
13973 xmlXPathCompOpEval(ctxt,
13974 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013975 if (ctxt->error != XPATH_EXPRESSION_OK) {
13976 xmlXPathFreeObject(obj);
13977 return(0);
13978 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013979
Daniel Veillardf06307e2001-07-03 10:35:50 +000013980 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000013981 if (res->type == XPATH_LOCATIONSET) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000013982 xmlLocationSetPtr rloc =
William M. Brack72ee48d2003-12-30 08:30:19 +000013983 (xmlLocationSetPtr)res->user;
13984 for (j=0; j<rloc->locNr; j++) {
13985 range = xmlXPtrNewRange(
13986 oldlocset->locTab[i]->user,
13987 oldlocset->locTab[i]->index,
13988 rloc->locTab[j]->user2,
13989 rloc->locTab[j]->index2);
13990 if (range != NULL) {
13991 xmlXPtrLocationSetAdd(newlocset, range);
13992 }
13993 }
13994 } else {
13995 range = xmlXPtrNewRangeNodeObject(
13996 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13997 if (range != NULL) {
13998 xmlXPtrLocationSetAdd(newlocset,range);
13999 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014000 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014001
Daniel Veillardf06307e2001-07-03 10:35:50 +000014002 /*
14003 * Cleanup
14004 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014005 if (res != NULL) {
14006 xmlXPathReleaseObject(ctxt->context, res);
14007 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014008 if (ctxt->value == tmp) {
14009 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014010 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000014011 }
14012
14013 ctxt->context->node = NULL;
14014 }
William M. Brack72ee48d2003-12-30 08:30:19 +000014015 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000014016 CHECK_TYPE0(XPATH_NODESET);
14017 obj = valuePop(ctxt);
14018 oldset = obj->nodesetval;
14019 ctxt->context->node = NULL;
14020
14021 newlocset = xmlXPtrLocationSetCreate(NULL);
14022
14023 if (oldset != NULL) {
14024 for (i = 0; i < oldset->nodeNr; i++) {
14025 /*
14026 * Run the evaluation with a node list made of a single item
14027 * in the nodeset.
14028 */
14029 ctxt->context->node = oldset->nodeTab[i];
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014030 /*
14031 * OPTIMIZE TODO: Avoid recreation for every iteration.
14032 */
14033 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14034 ctxt->context->node);
William M. Brack08171912003-12-29 02:52:11 +000014035 valuePush(ctxt, tmp);
14036
14037 if (op->ch2 != -1)
14038 total +=
14039 xmlXPathCompOpEval(ctxt,
14040 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000014041 if (ctxt->error != XPATH_EXPRESSION_OK) {
14042 xmlXPathFreeObject(obj);
14043 return(0);
14044 }
William M. Brack08171912003-12-29 02:52:11 +000014045
William M. Brack08171912003-12-29 02:52:11 +000014046 res = valuePop(ctxt);
14047 range =
14048 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
14049 res);
14050 if (range != NULL) {
14051 xmlXPtrLocationSetAdd(newlocset, range);
14052 }
14053
14054 /*
14055 * Cleanup
14056 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014057 if (res != NULL) {
14058 xmlXPathReleaseObject(ctxt->context, res);
14059 }
William M. Brack08171912003-12-29 02:52:11 +000014060 if (ctxt->value == tmp) {
14061 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014062 xmlXPathReleaseObject(ctxt->context, res);
William M. Brack08171912003-12-29 02:52:11 +000014063 }
14064
14065 ctxt->context->node = NULL;
14066 }
14067 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014068 }
14069
14070 /*
14071 * The result is used as the new evaluation set.
14072 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014073 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000014074 ctxt->context->node = NULL;
14075 ctxt->context->contextSize = -1;
14076 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000014077 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000014078 return (total);
14079 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014080#endif /* LIBXML_XPTR_ENABLED */
14081 }
14082 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000014083 "XPath: unknown precompiled operation %d\n", op->op);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080014084 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf06307e2001-07-03 10:35:50 +000014085 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014086}
14087
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014088/**
14089 * xmlXPathCompOpEvalToBoolean:
14090 * @ctxt: the XPath parser context
14091 *
14092 * Evaluates if the expression evaluates to true.
14093 *
14094 * Returns 1 if true, 0 if false and -1 on API or internal errors.
14095 */
14096static int
14097xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014098 xmlXPathStepOpPtr op,
14099 int isPredicate)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014100{
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014101 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014102
14103start:
14104 /* comp = ctxt->comp; */
14105 switch (op->op) {
14106 case XPATH_OP_END:
14107 return (0);
14108 case XPATH_OP_VALUE:
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014109 resObj = (xmlXPathObjectPtr) op->value4;
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000014110 if (isPredicate)
14111 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14112 return(xmlXPathCastToBoolean(resObj));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014113 case XPATH_OP_SORT:
14114 /*
14115 * We don't need sorting for boolean results. Skip this one.
14116 */
14117 if (op->ch1 != -1) {
14118 op = &ctxt->comp->steps[op->ch1];
14119 goto start;
14120 }
14121 return(0);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014122 case XPATH_OP_COLLECT:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014123 if (op->ch1 == -1)
14124 return(0);
14125
14126 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14127 if (ctxt->error != XPATH_EXPRESSION_OK)
14128 return(-1);
14129
14130 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14131 if (ctxt->error != XPATH_EXPRESSION_OK)
14132 return(-1);
14133
14134 resObj = valuePop(ctxt);
14135 if (resObj == NULL)
14136 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014137 break;
14138 default:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014139 /*
14140 * Fallback to call xmlXPathCompOpEval().
14141 */
14142 xmlXPathCompOpEval(ctxt, op);
14143 if (ctxt->error != XPATH_EXPRESSION_OK)
14144 return(-1);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014145
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014146 resObj = valuePop(ctxt);
14147 if (resObj == NULL)
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000014148 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014149 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014150 }
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014151
14152 if (resObj) {
14153 int res;
14154
14155 if (resObj->type == XPATH_BOOLEAN) {
14156 res = resObj->boolval;
14157 } else if (isPredicate) {
14158 /*
14159 * For predicates a result of type "number" is handled
14160 * differently:
14161 * SPEC XPath 1.0:
14162 * "If the result is a number, the result will be converted
14163 * to true if the number is equal to the context position
14164 * and will be converted to false otherwise;"
14165 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000014166 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014167 } else {
14168 res = xmlXPathCastToBoolean(resObj);
14169 }
14170 xmlXPathReleaseObject(ctxt->context, resObj);
14171 return(res);
14172 }
14173
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014174 return(0);
14175}
14176
Daniel Veillard56de87e2005-02-16 00:22:29 +000014177#ifdef XPATH_STREAMING
14178/**
14179 * xmlXPathRunStreamEval:
14180 * @ctxt: the XPath parser context with the compiled expression
14181 *
14182 * Evaluate the Precompiled Streamable XPath expression in the given context.
14183 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014184static int
14185xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14186 xmlXPathObjectPtr *resultSeq, int toBool)
14187{
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014188 int max_depth, min_depth;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014189 int from_root;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014190 int ret, depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014191 int eval_all_nodes;
William M. Brack12d37ab2005-02-21 13:54:07 +000014192 xmlNodePtr cur = NULL, limit = NULL;
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014193 xmlStreamCtxtPtr patstream = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014194
14195 int nb_nodes = 0;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014196
14197 if ((ctxt == NULL) || (comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014198 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014199 max_depth = xmlPatternMaxDepth(comp);
14200 if (max_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014201 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014202 if (max_depth == -2)
14203 max_depth = 10000;
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014204 min_depth = xmlPatternMinDepth(comp);
14205 if (min_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014206 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014207 from_root = xmlPatternFromRoot(comp);
14208 if (from_root < 0)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014209 return(-1);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014210#if 0
14211 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14212#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000014213
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014214 if (! toBool) {
14215 if (resultSeq == NULL)
14216 return(-1);
14217 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14218 if (*resultSeq == NULL)
14219 return(-1);
14220 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014221
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014222 /*
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014223 * handle the special cases of "/" amd "." being matched
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014224 */
14225 if (min_depth == 0) {
14226 if (from_root) {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014227 /* Select "/" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014228 if (toBool)
14229 return(1);
14230 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14231 (xmlNodePtr) ctxt->doc);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014232 } else {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014233 /* Select "self::node()" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014234 if (toBool)
14235 return(1);
14236 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014237 }
14238 }
14239 if (max_depth == 0) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014240 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014241 }
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014242
Daniel Veillard56de87e2005-02-16 00:22:29 +000014243 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000014244 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014245 } else if (ctxt->node != NULL) {
14246 switch (ctxt->node->type) {
14247 case XML_ELEMENT_NODE:
14248 case XML_DOCUMENT_NODE:
14249 case XML_DOCUMENT_FRAG_NODE:
14250 case XML_HTML_DOCUMENT_NODE:
14251#ifdef LIBXML_DOCB_ENABLED
14252 case XML_DOCB_DOCUMENT_NODE:
14253#endif
14254 cur = ctxt->node;
14255 break;
14256 case XML_ATTRIBUTE_NODE:
14257 case XML_TEXT_NODE:
14258 case XML_CDATA_SECTION_NODE:
14259 case XML_ENTITY_REF_NODE:
14260 case XML_ENTITY_NODE:
14261 case XML_PI_NODE:
14262 case XML_COMMENT_NODE:
14263 case XML_NOTATION_NODE:
14264 case XML_DTD_NODE:
14265 case XML_DOCUMENT_TYPE_NODE:
14266 case XML_ELEMENT_DECL:
14267 case XML_ATTRIBUTE_DECL:
14268 case XML_ENTITY_DECL:
14269 case XML_NAMESPACE_DECL:
14270 case XML_XINCLUDE_START:
14271 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000014272 break;
14273 }
14274 limit = cur;
14275 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014276 if (cur == NULL) {
14277 return(0);
14278 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014279
14280 patstream = xmlPatternGetStreamCtxt(comp);
14281 if (patstream == NULL) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014282 /*
14283 * QUESTION TODO: Is this an error?
14284 */
14285 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014286 }
14287
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014288 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014289
Daniel Veillard56de87e2005-02-16 00:22:29 +000014290 if (from_root) {
14291 ret = xmlStreamPush(patstream, NULL, NULL);
14292 if (ret < 0) {
14293 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014294 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014295 goto return_1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014296 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014297 }
14298 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014299 depth = 0;
14300 goto scan_children;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014301next_node:
Daniel Veillardd3ff7ef2006-02-27 19:43:17 +000014302 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014303 nb_nodes++;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014304
14305 switch (cur->type) {
14306 case XML_ELEMENT_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014307 case XML_TEXT_NODE:
14308 case XML_CDATA_SECTION_NODE:
14309 case XML_COMMENT_NODE:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014310 case XML_PI_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014311 if (cur->type == XML_ELEMENT_NODE) {
14312 ret = xmlStreamPush(patstream, cur->name,
Daniel Veillard56de87e2005-02-16 00:22:29 +000014313 (cur->ns ? cur->ns->href : NULL));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014314 } else if (eval_all_nodes)
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014315 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14316 else
14317 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014318
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014319 if (ret < 0) {
14320 /* NOP. */
14321 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014322 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014323 goto return_1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014324 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014325 }
14326 if ((cur->children == NULL) || (depth >= max_depth)) {
14327 ret = xmlStreamPop(patstream);
14328 while (cur->next != NULL) {
14329 cur = cur->next;
14330 if ((cur->type != XML_ENTITY_DECL) &&
14331 (cur->type != XML_DTD_NODE))
14332 goto next_node;
14333 }
14334 }
14335 default:
14336 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014337 }
14338
Daniel Veillard56de87e2005-02-16 00:22:29 +000014339scan_children:
Daniel Veillard3e62adb2012-08-09 14:24:02 +080014340 if (cur->type == XML_NAMESPACE_DECL) break;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014341 if ((cur->children != NULL) && (depth < max_depth)) {
14342 /*
Daniel Veillard45490ae2008-07-29 09:13:19 +000014343 * Do not descend on entities declarations
Daniel Veillard56de87e2005-02-16 00:22:29 +000014344 */
14345 if (cur->children->type != XML_ENTITY_DECL) {
14346 cur = cur->children;
14347 depth++;
14348 /*
14349 * Skip DTDs
14350 */
14351 if (cur->type != XML_DTD_NODE)
14352 continue;
14353 }
14354 }
14355
14356 if (cur == limit)
14357 break;
14358
14359 while (cur->next != NULL) {
14360 cur = cur->next;
14361 if ((cur->type != XML_ENTITY_DECL) &&
14362 (cur->type != XML_DTD_NODE))
14363 goto next_node;
14364 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014365
Daniel Veillard56de87e2005-02-16 00:22:29 +000014366 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014367 cur = cur->parent;
14368 depth--;
14369 if ((cur == NULL) || (cur == limit))
14370 goto done;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014371 if (cur->type == XML_ELEMENT_NODE) {
14372 ret = xmlStreamPop(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014373 } else if ((eval_all_nodes) &&
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014374 ((cur->type == XML_TEXT_NODE) ||
14375 (cur->type == XML_CDATA_SECTION_NODE) ||
14376 (cur->type == XML_COMMENT_NODE) ||
14377 (cur->type == XML_PI_NODE)))
14378 {
14379 ret = xmlStreamPop(patstream);
14380 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014381 if (cur->next != NULL) {
14382 cur = cur->next;
14383 break;
14384 }
14385 } while (cur != NULL);
14386
14387 } while ((cur != NULL) && (depth >= 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014388
Daniel Veillard56de87e2005-02-16 00:22:29 +000014389done:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014390
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014391#if 0
14392 printf("stream eval: checked %d nodes selected %d\n",
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014393 nb_nodes, retObj->nodesetval->nodeNr);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014394#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014395
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014396 if (patstream)
14397 xmlFreeStreamCtxt(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014398 return(0);
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014399
14400return_1:
14401 if (patstream)
14402 xmlFreeStreamCtxt(patstream);
14403 return(1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014404}
14405#endif /* XPATH_STREAMING */
14406
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014407/**
14408 * xmlXPathRunEval:
14409 * @ctxt: the XPath parser context with the compiled expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014410 * @toBool: evaluate to a boolean result
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014411 *
14412 * Evaluate the Precompiled XPath expression in the given context.
14413 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014414static int
14415xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14416{
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014417 xmlXPathCompExprPtr comp;
14418
14419 if ((ctxt == NULL) || (ctxt->comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014420 return(-1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014421
14422 if (ctxt->valueTab == NULL) {
14423 /* Allocate the value stack */
Daniel Veillard45490ae2008-07-29 09:13:19 +000014424 ctxt->valueTab = (xmlXPathObjectPtr *)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014425 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14426 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000014427 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014428 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014429 }
14430 ctxt->valueNr = 0;
14431 ctxt->valueMax = 10;
14432 ctxt->value = NULL;
Daniel Veillardf5048b32011-08-18 17:10:13 +080014433 ctxt->valueFrame = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014434 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014435#ifdef XPATH_STREAMING
14436 if (ctxt->comp->stream) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014437 int res;
14438
14439 if (toBool) {
14440 /*
14441 * Evaluation to boolean result.
14442 */
14443 res = xmlXPathRunStreamEval(ctxt->context,
14444 ctxt->comp->stream, NULL, 1);
14445 if (res != -1)
14446 return(res);
14447 } else {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014448 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014449
14450 /*
14451 * Evaluation to a sequence.
14452 */
14453 res = xmlXPathRunStreamEval(ctxt->context,
14454 ctxt->comp->stream, &resObj, 0);
14455
14456 if ((res != -1) && (resObj != NULL)) {
14457 valuePush(ctxt, resObj);
14458 return(0);
14459 }
14460 if (resObj != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +000014461 xmlXPathReleaseObject(ctxt->context, resObj);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014462 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014463 /*
14464 * QUESTION TODO: This falls back to normal XPath evaluation
14465 * if res == -1. Is this intended?
14466 */
Daniel Veillard56de87e2005-02-16 00:22:29 +000014467 }
14468#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014469 comp = ctxt->comp;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014470 if (comp->last < 0) {
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014471 xmlGenericError(xmlGenericErrorContext,
14472 "xmlXPathRunEval: last is less than zero\n");
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014473 return(-1);
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014474 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014475 if (toBool)
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014476 return(xmlXPathCompOpEvalToBoolean(ctxt,
14477 &comp->steps[comp->last], 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014478 else
14479 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14480
14481 return(0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014482}
14483
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014484/************************************************************************
14485 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +000014486 * Public interfaces *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014487 * *
14488 ************************************************************************/
14489
14490/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014491 * xmlXPathEvalPredicate:
14492 * @ctxt: the XPath context
14493 * @res: the Predicate Expression evaluation result
14494 *
14495 * Evaluate a predicate result for the current node.
14496 * A PredicateExpr is evaluated by evaluating the Expr and converting
14497 * the result to a boolean. If the result is a number, the result will
14498 * be converted to true if the number is equal to the position of the
14499 * context node in the context node list (as returned by the position
14500 * function) and will be converted to false otherwise; if the result
14501 * is not a number, then the result will be converted as if by a call
Daniel Veillard45490ae2008-07-29 09:13:19 +000014502 * to the boolean function.
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014503 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014504 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014505 */
14506int
14507xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014508 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014509 switch (res->type) {
14510 case XPATH_BOOLEAN:
14511 return(res->boolval);
14512 case XPATH_NUMBER:
14513 return(res->floatval == ctxt->proximityPosition);
14514 case XPATH_NODESET:
14515 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000014516 if (res->nodesetval == NULL)
14517 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014518 return(res->nodesetval->nodeNr != 0);
14519 case XPATH_STRING:
14520 return((res->stringval != NULL) &&
14521 (xmlStrlen(res->stringval) != 0));
14522 default:
14523 STRANGE
14524 }
14525 return(0);
14526}
14527
14528/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014529 * xmlXPathEvaluatePredicateResult:
14530 * @ctxt: the XPath Parser context
14531 * @res: the Predicate Expression evaluation result
14532 *
14533 * Evaluate a predicate result for the current node.
14534 * A PredicateExpr is evaluated by evaluating the Expr and converting
14535 * the result to a boolean. If the result is a number, the result will
14536 * be converted to true if the number is equal to the position of the
14537 * context node in the context node list (as returned by the position
14538 * function) and will be converted to false otherwise; if the result
14539 * is not a number, then the result will be converted as if by a call
Daniel Veillard45490ae2008-07-29 09:13:19 +000014540 * to the boolean function.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014541 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014542 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014543 */
14544int
Daniel Veillard45490ae2008-07-29 09:13:19 +000014545xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014546 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014547 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014548 switch (res->type) {
14549 case XPATH_BOOLEAN:
14550 return(res->boolval);
14551 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000014552#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000014553 return((res->floatval == ctxt->context->proximityPosition) &&
14554 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000014555#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014556 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000014557#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014558 case XPATH_NODESET:
14559 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000014560 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000014561 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014562 return(res->nodesetval->nodeNr != 0);
14563 case XPATH_STRING:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014564 return((res->stringval != NULL) && (res->stringval[0] != 0));
William M. Brack08171912003-12-29 02:52:11 +000014565#ifdef LIBXML_XPTR_ENABLED
14566 case XPATH_LOCATIONSET:{
14567 xmlLocationSetPtr ptr = res->user;
14568 if (ptr == NULL)
14569 return(0);
14570 return (ptr->locNr != 0);
14571 }
14572#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014573 default:
14574 STRANGE
14575 }
14576 return(0);
14577}
14578
Daniel Veillard56de87e2005-02-16 00:22:29 +000014579#ifdef XPATH_STREAMING
14580/**
14581 * xmlXPathTryStreamCompile:
14582 * @ctxt: an XPath context
14583 * @str: the XPath expression
14584 *
14585 * Try to compile the XPath expression as a streamable subset.
14586 *
14587 * Returns the compiled expression or NULL if failed to compile.
14588 */
14589static xmlXPathCompExprPtr
14590xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14591 /*
14592 * Optimization: use streaming patterns when the XPath expression can
14593 * be compiled to a stream lookup
14594 */
14595 xmlPatternPtr stream;
14596 xmlXPathCompExprPtr comp;
14597 xmlDictPtr dict = NULL;
14598 const xmlChar **namespaces = NULL;
14599 xmlNsPtr ns;
14600 int i, j;
14601
14602 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14603 (!xmlStrchr(str, '@'))) {
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014604 const xmlChar *tmp;
14605
14606 /*
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014607 * We don't try to handle expressions using the verbose axis
14608 * specifiers ("::"), just the simplied form at this point.
14609 * Additionally, if there is no list of namespaces available and
14610 * there's a ":" in the expression, indicating a prefixed QName,
14611 * then we won't try to compile either. xmlPatterncompile() needs
14612 * to have a list of namespaces at compilation time in order to
14613 * compile prefixed name tests.
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014614 */
14615 tmp = xmlStrchr(str, ':');
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014616 if ((tmp != NULL) &&
14617 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
Daniel Veillard45490ae2008-07-29 09:13:19 +000014618 return(NULL);
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014619
Daniel Veillard56de87e2005-02-16 00:22:29 +000014620 if (ctxt != NULL) {
14621 dict = ctxt->dict;
14622 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000014623 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000014624 if (namespaces == NULL) {
14625 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14626 return(NULL);
14627 }
14628 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14629 ns = ctxt->namespaces[j];
14630 namespaces[i++] = ns->href;
14631 namespaces[i++] = ns->prefix;
14632 }
14633 namespaces[i++] = NULL;
Daniel Veillard13cee4e2009-09-05 14:52:55 +020014634 namespaces[i] = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014635 }
14636 }
14637
William M. Brackea152c02005-06-09 18:12:28 +000014638 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14639 &namespaces[0]);
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014640 if (namespaces != NULL) {
14641 xmlFree((xmlChar **)namespaces);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014642 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014643 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14644 comp = xmlXPathNewCompExpr();
14645 if (comp == NULL) {
14646 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14647 return(NULL);
14648 }
14649 comp->stream = stream;
14650 comp->dict = dict;
14651 if (comp->dict)
14652 xmlDictReference(comp->dict);
14653 return(comp);
14654 }
14655 xmlFreePattern(stream);
14656 }
14657 return(NULL);
14658}
14659#endif /* XPATH_STREAMING */
14660
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014661static void
Nick Wellnhofer62270532012-08-19 19:42:38 +020014662xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014663{
14664 /*
14665 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14666 * internal representation.
14667 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014668
Nick Wellnhofer62270532012-08-19 19:42:38 +020014669 if ((op->ch1 != -1) &&
14670 (op->op == XPATH_OP_COLLECT /* 11 */))
14671 {
14672 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14673
14674 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14675 ((xmlXPathAxisVal) prevop->value ==
14676 AXIS_DESCENDANT_OR_SELF) &&
14677 (prevop->ch2 == -1) &&
14678 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14679 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14680 {
14681 /*
14682 * This is a "descendant-or-self::node()" without predicates.
14683 * Try to eliminate it.
14684 */
14685
14686 switch ((xmlXPathAxisVal) op->value) {
14687 case AXIS_CHILD:
14688 case AXIS_DESCENDANT:
14689 /*
14690 * Convert "descendant-or-self::node()/child::" or
14691 * "descendant-or-self::node()/descendant::" to
14692 * "descendant::"
14693 */
14694 op->ch1 = prevop->ch1;
14695 op->value = AXIS_DESCENDANT;
14696 break;
14697 case AXIS_SELF:
14698 case AXIS_DESCENDANT_OR_SELF:
14699 /*
14700 * Convert "descendant-or-self::node()/self::" or
14701 * "descendant-or-self::node()/descendant-or-self::" to
14702 * to "descendant-or-self::"
14703 */
14704 op->ch1 = prevop->ch1;
14705 op->value = AXIS_DESCENDANT_OR_SELF;
14706 break;
14707 default:
14708 break;
14709 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014710 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014711 }
Nick Wellnhofer62270532012-08-19 19:42:38 +020014712
14713 /* Recurse */
14714 if (op->ch1 != -1)
14715 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014716 if (op->ch2 != -1)
Nick Wellnhofer62270532012-08-19 19:42:38 +020014717 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014718}
14719
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014720/**
Daniel Veillard4773df22004-01-23 13:15:13 +000014721 * xmlXPathCtxtCompile:
14722 * @ctxt: an XPath context
14723 * @str: the XPath expression
14724 *
14725 * Compile an XPath expression
14726 *
14727 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14728 * the caller has to free the object.
14729 */
14730xmlXPathCompExprPtr
14731xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14732 xmlXPathParserContextPtr pctxt;
14733 xmlXPathCompExprPtr comp;
14734
Daniel Veillard56de87e2005-02-16 00:22:29 +000014735#ifdef XPATH_STREAMING
14736 comp = xmlXPathTryStreamCompile(ctxt, str);
14737 if (comp != NULL)
14738 return(comp);
14739#endif
14740
Daniel Veillard4773df22004-01-23 13:15:13 +000014741 xmlXPathInit();
14742
14743 pctxt = xmlXPathNewParserContext(str, ctxt);
William M. Brack11be2d02007-01-24 19:17:19 +000014744 if (pctxt == NULL)
14745 return NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014746 xmlXPathCompileExpr(pctxt, 1);
Daniel Veillard4773df22004-01-23 13:15:13 +000014747
14748 if( pctxt->error != XPATH_EXPRESSION_OK )
14749 {
14750 xmlXPathFreeParserContext(pctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000014751 return(NULL);
Daniel Veillard4773df22004-01-23 13:15:13 +000014752 }
14753
14754 if (*pctxt->cur != 0) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014755 /*
Daniel Veillard4773df22004-01-23 13:15:13 +000014756 * aleksey: in some cases this line prints *second* error message
14757 * (see bug #78858) and probably this should be fixed.
14758 * However, we are not sure that all error messages are printed
14759 * out in other places. It's not critical so we leave it as-is for now
14760 */
14761 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14762 comp = NULL;
14763 } else {
14764 comp = pctxt->comp;
14765 pctxt->comp = NULL;
14766 }
14767 xmlXPathFreeParserContext(pctxt);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014768
Daniel Veillard4773df22004-01-23 13:15:13 +000014769 if (comp != NULL) {
14770 comp->expr = xmlStrdup(str);
14771#ifdef DEBUG_EVAL_COUNTS
14772 comp->string = xmlStrdup(str);
14773 comp->nb = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014774#endif
Nick Wellnhofer62270532012-08-19 19:42:38 +020014775 if ((comp->nbStep > 1) && (comp->last >= 0)) {
14776 xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014777 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014778 }
Daniel Veillard4773df22004-01-23 13:15:13 +000014779 return(comp);
14780}
14781
14782/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014783 * xmlXPathCompile:
14784 * @str: the XPath expression
14785 *
14786 * Compile an XPath expression
14787 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000014788 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014789 * the caller has to free the object.
14790 */
14791xmlXPathCompExprPtr
14792xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000014793 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014794}
14795
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014796/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014797 * xmlXPathCompiledEvalInternal:
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014798 * @comp: the compiled XPath expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014799 * @ctxt: the XPath context
14800 * @resObj: the resulting XPath object or NULL
14801 * @toBool: 1 if only a boolean result is requested
Owen Taylor3473f882001-02-23 17:55:21 +000014802 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014803 * Evaluate the Precompiled XPath expression in the given context.
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014804 * The caller has to free @resObj.
Owen Taylor3473f882001-02-23 17:55:21 +000014805 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014806 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000014807 * the caller has to free the object.
14808 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014809static int
14810xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14811 xmlXPathContextPtr ctxt,
14812 xmlXPathObjectPtr *resObj,
14813 int toBool)
14814{
Daniel Veillard45490ae2008-07-29 09:13:19 +000014815 xmlXPathParserContextPtr pctxt;
Daniel Veillard81463942001-10-16 12:34:39 +000014816#ifndef LIBXML_THREAD_ENABLED
14817 static int reentance = 0;
14818#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014819 int res;
Owen Taylor3473f882001-02-23 17:55:21 +000014820
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014821 CHECK_CTXT_NEG(ctxt)
William M. Brackf13f77f2004-11-12 16:03:48 +000014822
14823 if (comp == NULL)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014824 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +000014825 xmlXPathInit();
14826
Daniel Veillard81463942001-10-16 12:34:39 +000014827#ifndef LIBXML_THREAD_ENABLED
14828 reentance++;
14829 if (reentance > 1)
14830 xmlXPathDisableOptimizer = 1;
14831#endif
14832
Daniel Veillardf06307e2001-07-03 10:35:50 +000014833#ifdef DEBUG_EVAL_COUNTS
14834 comp->nb++;
14835 if ((comp->string != NULL) && (comp->nb > 100)) {
14836 fprintf(stderr, "100 x %s\n", comp->string);
14837 comp->nb = 0;
14838 }
14839#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014840 pctxt = xmlXPathCompParserContext(comp, ctxt);
14841 res = xmlXPathRunEval(pctxt, toBool);
Owen Taylor3473f882001-02-23 17:55:21 +000014842
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014843 if (resObj) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014844 if (pctxt->value == NULL) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014845 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014846 "xmlXPathCompiledEval: evaluation failed\n");
Daniel Veillard45490ae2008-07-29 09:13:19 +000014847 *resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014848 } else {
14849 *resObj = valuePop(pctxt);
14850 }
Owen Taylor3473f882001-02-23 17:55:21 +000014851 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014852
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014853 /*
14854 * Pop all remaining objects from the stack.
14855 */
14856 if (pctxt->valueNr > 0) {
14857 xmlXPathObjectPtr tmp;
14858 int stack = 0;
14859
14860 do {
14861 tmp = valuePop(pctxt);
14862 if (tmp != NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014863 stack++;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014864 xmlXPathReleaseObject(ctxt, tmp);
14865 }
14866 } while (tmp != NULL);
14867 if ((stack != 0) &&
14868 ((toBool) || ((resObj) && (*resObj))))
14869 {
14870 xmlGenericError(xmlGenericErrorContext,
14871 "xmlXPathCompiledEval: %d objects left on the stack.\n",
14872 stack);
14873 }
Owen Taylor3473f882001-02-23 17:55:21 +000014874 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014875
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014876 if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14877 xmlXPathFreeObject(*resObj);
14878 *resObj = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014879 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014880 pctxt->comp = NULL;
14881 xmlXPathFreeParserContext(pctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000014882#ifndef LIBXML_THREAD_ENABLED
14883 reentance--;
14884#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014885
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014886 return(res);
14887}
14888
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014889/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014890 * xmlXPathCompiledEval:
14891 * @comp: the compiled XPath expression
14892 * @ctx: the XPath context
14893 *
14894 * Evaluate the Precompiled XPath expression in the given context.
14895 *
14896 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14897 * the caller has to free the object.
14898 */
14899xmlXPathObjectPtr
14900xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14901{
14902 xmlXPathObjectPtr res = NULL;
14903
14904 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14905 return(res);
14906}
14907
14908/**
14909 * xmlXPathCompiledEvalToBoolean:
14910 * @comp: the compiled XPath expression
14911 * @ctxt: the XPath context
14912 *
14913 * Applies the XPath boolean() function on the result of the given
14914 * compiled expression.
14915 *
14916 * Returns 1 if the expression evaluated to true, 0 if to false and
14917 * -1 in API and internal errors.
14918 */
14919int
14920xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14921 xmlXPathContextPtr ctxt)
14922{
14923 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14924}
14925
14926/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014927 * xmlXPathEvalExpr:
14928 * @ctxt: the XPath Parser context
14929 *
14930 * Parse and evaluate an XPath expression in the given context,
14931 * then push the result on the context stack
14932 */
14933void
14934xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014935#ifdef XPATH_STREAMING
14936 xmlXPathCompExprPtr comp;
14937#endif
14938
Daniel Veillarda82b1822004-11-08 16:24:57 +000014939 if (ctxt == NULL) return;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014940
Daniel Veillard56de87e2005-02-16 00:22:29 +000014941#ifdef XPATH_STREAMING
14942 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14943 if (comp != NULL) {
14944 if (ctxt->comp != NULL)
14945 xmlXPathFreeCompExpr(ctxt->comp);
14946 ctxt->comp = comp;
14947 if (ctxt->cur != NULL)
14948 while (*ctxt->cur != 0) ctxt->cur++;
14949 } else
14950#endif
14951 {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014952 xmlXPathCompileExpr(ctxt, 1);
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014953 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
14954 (ctxt->comp != NULL) &&
Nick Wellnhofer62270532012-08-19 19:42:38 +020014955 (ctxt->comp->nbStep > 1) &&
14956 (ctxt->comp->last >= 0))
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014957 {
Nick Wellnhofer62270532012-08-19 19:42:38 +020014958 xmlXPathOptimizeExpression(ctxt->comp,
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014959 &ctxt->comp->steps[ctxt->comp->last]);
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014960 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014961 }
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000014962 CHECK_ERROR;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014963 xmlXPathRunEval(ctxt, 0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014964}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014965
14966/**
14967 * xmlXPathEval:
14968 * @str: the XPath expression
14969 * @ctx: the XPath context
14970 *
14971 * Evaluate the XPath Location Path in the given context.
14972 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014973 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014974 * the caller has to free the object.
14975 */
14976xmlXPathObjectPtr
14977xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14978 xmlXPathParserContextPtr ctxt;
14979 xmlXPathObjectPtr res, tmp, init = NULL;
14980 int stack = 0;
14981
William M. Brackf13f77f2004-11-12 16:03:48 +000014982 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014983
William M. Brackf13f77f2004-11-12 16:03:48 +000014984 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014985
14986 ctxt = xmlXPathNewParserContext(str, ctx);
William M. Brack11be2d02007-01-24 19:17:19 +000014987 if (ctxt == NULL)
14988 return NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014989 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014990
14991 if (ctxt->value == NULL) {
14992 xmlGenericError(xmlGenericErrorContext,
14993 "xmlXPathEval: evaluation failed\n");
14994 res = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014995 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
Daniel Veillard56de87e2005-02-16 00:22:29 +000014996#ifdef XPATH_STREAMING
14997 && (ctxt->comp->stream == NULL)
14998#endif
14999 ) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015000 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
15001 res = NULL;
15002 } else {
15003 res = valuePop(ctxt);
15004 }
15005
15006 do {
15007 tmp = valuePop(ctxt);
15008 if (tmp != NULL) {
15009 if (tmp != init)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015010 stack++;
15011 xmlXPathReleaseObject(ctx, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000015012 }
15013 } while (tmp != NULL);
15014 if ((stack != 0) && (res != NULL)) {
15015 xmlGenericError(xmlGenericErrorContext,
15016 "xmlXPathEval: %d object left on the stack\n",
15017 stack);
15018 }
15019 if (ctxt->error != XPATH_EXPRESSION_OK) {
15020 xmlXPathFreeObject(res);
15021 res = NULL;
15022 }
15023
Owen Taylor3473f882001-02-23 17:55:21 +000015024 xmlXPathFreeParserContext(ctxt);
15025 return(res);
15026}
15027
15028/**
15029 * xmlXPathEvalExpression:
15030 * @str: the XPath expression
15031 * @ctxt: the XPath context
15032 *
15033 * Evaluate the XPath expression in the given context.
15034 *
15035 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15036 * the caller has to free the object.
15037 */
15038xmlXPathObjectPtr
15039xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
15040 xmlXPathParserContextPtr pctxt;
15041 xmlXPathObjectPtr res, tmp;
15042 int stack = 0;
15043
William M. Brackf13f77f2004-11-12 16:03:48 +000015044 CHECK_CTXT(ctxt)
Owen Taylor3473f882001-02-23 17:55:21 +000015045
William M. Brackf13f77f2004-11-12 16:03:48 +000015046 xmlXPathInit();
Owen Taylor3473f882001-02-23 17:55:21 +000015047
15048 pctxt = xmlXPathNewParserContext(str, ctxt);
William M. Brack11be2d02007-01-24 19:17:19 +000015049 if (pctxt == NULL)
15050 return NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000015051 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000015052
Daniel Veillardc465ffc2006-10-17 19:39:33 +000015053 if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
Owen Taylor3473f882001-02-23 17:55:21 +000015054 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
15055 res = NULL;
15056 } else {
15057 res = valuePop(pctxt);
15058 }
15059 do {
15060 tmp = valuePop(pctxt);
15061 if (tmp != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015062 xmlXPathReleaseObject(ctxt, tmp);
Owen Taylor3473f882001-02-23 17:55:21 +000015063 stack++;
15064 }
15065 } while (tmp != NULL);
15066 if ((stack != 0) && (res != NULL)) {
15067 xmlGenericError(xmlGenericErrorContext,
15068 "xmlXPathEvalExpression: %d object left on the stack\n",
15069 stack);
15070 }
15071 xmlXPathFreeParserContext(pctxt);
15072 return(res);
15073}
15074
Daniel Veillard42766c02002-08-22 20:52:17 +000015075/************************************************************************
15076 * *
15077 * Extra functions not pertaining to the XPath spec *
15078 * *
15079 ************************************************************************/
15080/**
15081 * xmlXPathEscapeUriFunction:
15082 * @ctxt: the XPath Parser context
15083 * @nargs: the number of arguments
15084 *
15085 * Implement the escape-uri() XPath function
15086 * string escape-uri(string $str, bool $escape-reserved)
15087 *
15088 * This function applies the URI escaping rules defined in section 2 of [RFC
15089 * 2396] to the string supplied as $uri-part, which typically represents all
15090 * or part of a URI. The effect of the function is to replace any special
15091 * character in the string by an escape sequence of the form %xx%yy...,
15092 * where xxyy... is the hexadecimal representation of the octets used to
15093 * represent the character in UTF-8.
15094 *
15095 * The set of characters that are escaped depends on the setting of the
15096 * boolean argument $escape-reserved.
15097 *
15098 * If $escape-reserved is true, all characters are escaped other than lower
15099 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15100 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15101 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15102 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15103 * A-F).
15104 *
15105 * If $escape-reserved is false, the behavior differs in that characters
15106 * referred to in [RFC 2396] as reserved characters are not escaped. These
15107 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
Daniel Veillard45490ae2008-07-29 09:13:19 +000015108 *
Daniel Veillard42766c02002-08-22 20:52:17 +000015109 * [RFC 2396] does not define whether escaped URIs should use lower case or
15110 * upper case for hexadecimal digits. To ensure that escaped URIs can be
15111 * compared using string comparison functions, this function must always use
15112 * the upper-case letters A-F.
Daniel Veillard45490ae2008-07-29 09:13:19 +000015113 *
Daniel Veillard42766c02002-08-22 20:52:17 +000015114 * Generally, $escape-reserved should be set to true when escaping a string
15115 * that is to form a single part of a URI, and to false when escaping an
15116 * entire URI or URI reference.
Daniel Veillard45490ae2008-07-29 09:13:19 +000015117 *
15118 * In the case of non-ascii characters, the string is encoded according to
Daniel Veillard42766c02002-08-22 20:52:17 +000015119 * utf-8 and then converted according to RFC 2396.
15120 *
15121 * Examples
Daniel Veillard45490ae2008-07-29 09:13:19 +000015122 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
Daniel Veillard42766c02002-08-22 20:52:17 +000015123 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15124 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15125 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15126 *
15127 */
Daniel Veillard118aed72002-09-24 14:13:13 +000015128static void
Daniel Veillard42766c02002-08-22 20:52:17 +000015129xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15130 xmlXPathObjectPtr str;
15131 int escape_reserved;
Daniel Veillardade10f22012-07-12 09:43:27 +080015132 xmlBufPtr target;
Daniel Veillard42766c02002-08-22 20:52:17 +000015133 xmlChar *cptr;
15134 xmlChar escape[4];
Daniel Veillard45490ae2008-07-29 09:13:19 +000015135
Daniel Veillard42766c02002-08-22 20:52:17 +000015136 CHECK_ARITY(2);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015137
Daniel Veillard42766c02002-08-22 20:52:17 +000015138 escape_reserved = xmlXPathPopBoolean(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015139
Daniel Veillard42766c02002-08-22 20:52:17 +000015140 CAST_TO_STRING;
15141 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015142
Daniel Veillardade10f22012-07-12 09:43:27 +080015143 target = xmlBufCreate();
Daniel Veillard45490ae2008-07-29 09:13:19 +000015144
Daniel Veillard42766c02002-08-22 20:52:17 +000015145 escape[0] = '%';
15146 escape[3] = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000015147
Daniel Veillard42766c02002-08-22 20:52:17 +000015148 if (target) {
15149 for (cptr = str->stringval; *cptr; cptr++) {
15150 if ((*cptr >= 'A' && *cptr <= 'Z') ||
15151 (*cptr >= 'a' && *cptr <= 'z') ||
15152 (*cptr >= '0' && *cptr <= '9') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000015153 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
Daniel Veillard42766c02002-08-22 20:52:17 +000015154 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
15155 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000015156 (*cptr == '%' &&
Daniel Veillard42766c02002-08-22 20:52:17 +000015157 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15158 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15159 (cptr[1] >= '0' && cptr[1] <= '9')) &&
15160 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15161 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15162 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15163 (!escape_reserved &&
15164 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15165 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15166 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15167 *cptr == ','))) {
Daniel Veillardade10f22012-07-12 09:43:27 +080015168 xmlBufAdd(target, cptr, 1);
Daniel Veillard42766c02002-08-22 20:52:17 +000015169 } else {
15170 if ((*cptr >> 4) < 10)
15171 escape[1] = '0' + (*cptr >> 4);
15172 else
15173 escape[1] = 'A' - 10 + (*cptr >> 4);
15174 if ((*cptr & 0xF) < 10)
15175 escape[2] = '0' + (*cptr & 0xF);
15176 else
15177 escape[2] = 'A' - 10 + (*cptr & 0xF);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015178
Daniel Veillardade10f22012-07-12 09:43:27 +080015179 xmlBufAdd(target, &escape[0], 3);
Daniel Veillard42766c02002-08-22 20:52:17 +000015180 }
15181 }
15182 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015183 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +080015184 xmlBufContent(target)));
15185 xmlBufFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015186 xmlXPathReleaseObject(ctxt->context, str);
Daniel Veillard42766c02002-08-22 20:52:17 +000015187}
15188
Owen Taylor3473f882001-02-23 17:55:21 +000015189/**
15190 * xmlXPathRegisterAllFunctions:
15191 * @ctxt: the XPath context
15192 *
15193 * Registers all default XPath functions in this context
15194 */
15195void
15196xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15197{
15198 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15199 xmlXPathBooleanFunction);
15200 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15201 xmlXPathCeilingFunction);
15202 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15203 xmlXPathCountFunction);
15204 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15205 xmlXPathConcatFunction);
15206 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15207 xmlXPathContainsFunction);
15208 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15209 xmlXPathIdFunction);
15210 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15211 xmlXPathFalseFunction);
15212 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15213 xmlXPathFloorFunction);
15214 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15215 xmlXPathLastFunction);
15216 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15217 xmlXPathLangFunction);
15218 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15219 xmlXPathLocalNameFunction);
15220 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15221 xmlXPathNotFunction);
15222 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15223 xmlXPathNameFunction);
15224 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15225 xmlXPathNamespaceURIFunction);
15226 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15227 xmlXPathNormalizeFunction);
15228 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15229 xmlXPathNumberFunction);
15230 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15231 xmlXPathPositionFunction);
15232 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15233 xmlXPathRoundFunction);
15234 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15235 xmlXPathStringFunction);
15236 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15237 xmlXPathStringLengthFunction);
15238 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15239 xmlXPathStartsWithFunction);
15240 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15241 xmlXPathSubstringFunction);
15242 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15243 xmlXPathSubstringBeforeFunction);
15244 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15245 xmlXPathSubstringAfterFunction);
15246 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15247 xmlXPathSumFunction);
15248 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15249 xmlXPathTrueFunction);
15250 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15251 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000015252
15253 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15254 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15255 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000015256}
15257
15258#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000015259#define bottom_xpath
15260#include "elfgcchack.h"