blob: ec02a169e815dd08baad5df8157a0ef5897c5ca0 [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
William M. Brackd1757ab2004-10-02 22:07:48 +000069/*
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000070* XP_OPTIMIZED_NON_ELEM_COMPARISON:
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +000071* If defined, this will use xmlXPathCmpNodesExt() instead of
72* xmlXPathCmpNodes(). The new function is optimized comparison of
73* non-element nodes; actually it will speed up comparison only if
74* xmlXPathOrderDocElems() was called in order to index the elements of
75* a tree in document order; Libxslt does such an indexing, thus it will
76* benefit from this optimization.
77*/
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000078#define XP_OPTIMIZED_NON_ELEM_COMPARISON
79
80/*
81* XP_OPTIMIZED_FILTER_FIRST:
82* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
83* in a way, that it stop evaluation at the first node.
Daniel Veillard45490ae2008-07-29 09:13:19 +000084*/
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000085#define XP_OPTIMIZED_FILTER_FIRST
86
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000087/*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000088* XP_DEBUG_OBJ_USAGE:
89* Internal flag to enable tracking of how much XPath objects have been
90* created.
91*/
92/* #define XP_DEBUG_OBJ_USAGE */
93
94/*
Daniel Veillardcd852ad2012-07-30 10:12:18 +080095 * XPATH_MAX_STEPS:
96 * when compiling an XPath expression we arbitrary limit the maximum
97 * number of step operation in the compiled expression. 1000000 is
98 * an insanely large value which should never be reached under normal
99 * circumstances
100 */
101#define XPATH_MAX_STEPS 1000000
102
103/*
104 * XPATH_MAX_STACK_DEPTH:
105 * when evaluating an XPath expression we arbitrary limit the maximum
106 * number of object allowed to be pushed on the stack. 1000000 is
107 * an insanely large value which should never be reached under normal
108 * circumstances
109 */
110#define XPATH_MAX_STACK_DEPTH 1000000
111
112/*
113 * XPATH_MAX_NODESET_LENGTH:
114 * when evaluating an XPath expression nodesets are created and we
115 * arbitrary limit the maximum length of those node set. 10000000 is
116 * an insanely large value which should never be reached under normal
117 * circumstances, one would first need to construct an in memory tree
118 * with more than 10 millions nodes.
119 */
120#define XPATH_MAX_NODESET_LENGTH 10000000
121
122/*
William M. Brackd1757ab2004-10-02 22:07:48 +0000123 * TODO:
124 * There are a few spots where some tests are done which depend upon ascii
125 * data. These should be enhanced for full UTF8 support (see particularly
126 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
127 */
Kasimier T. Buchcik97258712006-01-05 12:30:43 +0000128
William M. Brack21e4ef22005-01-02 09:53:13 +0000129#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000130
131/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000132 * *
133 * Floating point stuff *
134 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000135 ************************************************************************/
136
Daniel Veillardc0631a62001-09-20 13:56:06 +0000137#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +0000138#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +0000139#endif
Daniel Veillardcda96922001-08-21 10:56:31 +0000140#include "trionan.c"
141
Owen Taylor3473f882001-02-23 17:55:21 +0000142/*
Owen Taylor3473f882001-02-23 17:55:21 +0000143 * The lack of portability of this section of the libc is annoying !
144 */
145double xmlXPathNAN = 0;
146double xmlXPathPINF = 1;
147double xmlXPathNINF = -1;
Daniel Veillard24505b02005-07-28 23:49:35 +0000148static double xmlXPathNZERO = 0; /* not exported from headers */
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000149static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000150
Owen Taylor3473f882001-02-23 17:55:21 +0000151/**
152 * xmlXPathInit:
153 *
154 * Initialize the XPath environment
155 */
156void
157xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000158 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +0000159
Bjorn Reese45029602001-08-21 09:23:53 +0000160 xmlXPathPINF = trio_pinf();
161 xmlXPathNINF = trio_ninf();
162 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000163 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +0000164
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000165 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000166}
167
Daniel Veillardcda96922001-08-21 10:56:31 +0000168/**
169 * xmlXPathIsNaN:
170 * @val: a double value
171 *
172 * Provides a portable isnan() function to detect whether a double
173 * is a NotaNumber. Based on trio code
174 * http://sourceforge.net/projects/ctrio/
Daniel Veillard45490ae2008-07-29 09:13:19 +0000175 *
Daniel Veillardcda96922001-08-21 10:56:31 +0000176 * Returns 1 if the value is a NaN, 0 otherwise
177 */
178int
179xmlXPathIsNaN(double val) {
180 return(trio_isnan(val));
181}
182
183/**
184 * xmlXPathIsInf:
185 * @val: a double value
186 *
187 * Provides a portable isinf() function to detect whether a double
188 * is a +Infinite or -Infinite. Based on trio code
189 * http://sourceforge.net/projects/ctrio/
Daniel Veillard45490ae2008-07-29 09:13:19 +0000190 *
Daniel Veillardcda96922001-08-21 10:56:31 +0000191 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
192 */
193int
194xmlXPathIsInf(double val) {
195 return(trio_isinf(val));
196}
197
Daniel Veillard4432df22003-09-28 18:58:27 +0000198#endif /* SCHEMAS or XPATH */
199#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000200/**
201 * xmlXPathGetSign:
202 * @val: a double value
203 *
204 * Provides a portable function to detect the sign of a double
205 * Modified from trio code
206 * http://sourceforge.net/projects/ctrio/
Daniel Veillard45490ae2008-07-29 09:13:19 +0000207 *
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000208 * Returns 1 if the value is Negative, 0 if positive
209 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000210static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000211xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000212 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000213}
214
215
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000216/*
217 * TODO: when compatibility allows remove all "fake node libxslt" strings
218 * the test should just be name[0] = ' '
219 */
Daniel Veillard074f37e2008-09-01 13:38:22 +0000220#ifdef DEBUG_XPATH_EXPRESSION
221#define DEBUG_STEP
222#define DEBUG_EXPR
223#define DEBUG_EVAL_COUNTS
224#endif
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000225
226static xmlNs xmlXPathXMLNamespaceStruct = {
227 NULL,
228 XML_NAMESPACE_DECL,
229 XML_XML_NAMESPACE,
230 BAD_CAST "xml",
William M. Brackee0b9822007-03-07 08:15:01 +0000231 NULL,
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000232 NULL
233};
234static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
235#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard45490ae2008-07-29 09:13:19 +0000236/*
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000237 * Optimizer is disabled only when threaded apps are detected while
238 * the library ain't compiled for thread safety.
239 */
240static int xmlXPathDisableOptimizer = 0;
241#endif
242
Owen Taylor3473f882001-02-23 17:55:21 +0000243/************************************************************************
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000244 * *
245 * Error handling routines *
246 * *
247 ************************************************************************/
248
Daniel Veillard24505b02005-07-28 23:49:35 +0000249/**
250 * XP_ERRORNULL:
251 * @X: the error code
252 *
253 * Macro to raise an XPath error and return NULL.
254 */
255#define XP_ERRORNULL(X) \
256 { xmlXPathErr(ctxt, X); return(NULL); }
257
William M. Brack08171912003-12-29 02:52:11 +0000258/*
259 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
260 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000261static const char *xmlXPathErrorMessages[] = {
262 "Ok\n",
263 "Number encoding\n",
264 "Unfinished literal\n",
265 "Start of literal\n",
266 "Expected $ for variable reference\n",
267 "Undefined variable\n",
268 "Invalid predicate\n",
269 "Invalid expression\n",
270 "Missing closing curly brace\n",
271 "Unregistered function\n",
272 "Invalid operand\n",
273 "Invalid type\n",
274 "Invalid number of arguments\n",
275 "Invalid context size\n",
276 "Invalid context position\n",
277 "Memory allocation error\n",
278 "Syntax error\n",
279 "Resource error\n",
280 "Sub resource error\n",
281 "Undefined namespace prefix\n",
282 "Encoding error\n",
Daniel Veillard57b25162004-11-06 14:50:18 +0000283 "Char out of XML range\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000284 "Invalid or incomplete context\n",
Daniel Veillardf5048b32011-08-18 17:10:13 +0800285 "Stack usage errror\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000286 "?? Unknown error ??\n" /* Must be last in the list! */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000287};
William M. Brackcd65bc92005-01-06 09:39:18 +0000288#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
289 sizeof(xmlXPathErrorMessages[0])) - 1)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000290/**
291 * xmlXPathErrMemory:
292 * @ctxt: an XPath context
293 * @extra: extra informations
294 *
295 * Handle a redefinition of attribute error
296 */
297static void
298xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
299{
300 if (ctxt != NULL) {
301 if (extra) {
302 xmlChar buf[200];
303
304 xmlStrPrintf(buf, 200,
305 BAD_CAST "Memory allocation failed : %s\n",
306 extra);
307 ctxt->lastError.message = (char *) xmlStrdup(buf);
308 } else {
309 ctxt->lastError.message = (char *)
310 xmlStrdup(BAD_CAST "Memory allocation failed\n");
311 }
312 ctxt->lastError.domain = XML_FROM_XPATH;
313 ctxt->lastError.code = XML_ERR_NO_MEMORY;
314 if (ctxt->error != NULL)
315 ctxt->error(ctxt->userData, &ctxt->lastError);
316 } else {
317 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000318 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000319 NULL, NULL, XML_FROM_XPATH,
320 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
321 extra, NULL, NULL, 0, 0,
322 "Memory allocation failed : %s\n", extra);
323 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000324 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000325 NULL, NULL, XML_FROM_XPATH,
326 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
327 NULL, NULL, NULL, 0, 0,
328 "Memory allocation failed\n");
329 }
330}
331
332/**
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000333 * xmlXPathPErrMemory:
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000334 * @ctxt: an XPath parser context
335 * @extra: extra informations
336 *
337 * Handle a redefinition of attribute error
338 */
339static void
340xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
341{
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000342 if (ctxt == NULL)
343 xmlXPathErrMemory(NULL, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000344 else {
345 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000346 xmlXPathErrMemory(ctxt->context, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000347 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000348}
349
350/**
351 * xmlXPathErr:
352 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000353 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000354 *
William M. Brackcd65bc92005-01-06 09:39:18 +0000355 * Handle an XPath error
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000356 */
357void
358xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
359{
William M. Brackcd65bc92005-01-06 09:39:18 +0000360 if ((error < 0) || (error > MAXERRNO))
361 error = MAXERRNO;
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000362 if (ctxt == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000363 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000364 NULL, NULL, XML_FROM_XPATH,
365 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
366 XML_ERR_ERROR, NULL, 0,
367 NULL, NULL, NULL, 0, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200368 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000369 return;
370 }
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000371 ctxt->error = error;
372 if (ctxt->context == NULL) {
373 __xmlRaiseError(NULL, NULL, NULL,
374 NULL, NULL, XML_FROM_XPATH,
375 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
376 XML_ERR_ERROR, NULL, 0,
377 (const char *) ctxt->base, NULL, NULL,
378 ctxt->cur - ctxt->base, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200379 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000380 return;
381 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +0000382
383 /* cleanup current last error */
Daniel Veillard45490ae2008-07-29 09:13:19 +0000384 xmlResetError(&ctxt->context->lastError);
Aleksey Sanin1b2be102006-05-31 20:53:43 +0000385
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000386 ctxt->context->lastError.domain = XML_FROM_XPATH;
387 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
388 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000389 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000390 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
391 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
392 ctxt->context->lastError.node = ctxt->context->debugNode;
393 if (ctxt->context->error != NULL) {
394 ctxt->context->error(ctxt->context->userData,
395 &ctxt->context->lastError);
396 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000397 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000398 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
399 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
400 XML_ERR_ERROR, NULL, 0,
401 (const char *) ctxt->base, NULL, NULL,
402 ctxt->cur - ctxt->base, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200403 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000404 }
405
406}
407
408/**
409 * xmlXPatherror:
410 * @ctxt: the XPath Parser context
411 * @file: the file name
412 * @line: the line number
413 * @no: the error number
414 *
415 * Formats an error message.
416 */
417void
418xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
419 int line ATTRIBUTE_UNUSED, int no) {
420 xmlXPathErr(ctxt, no);
421}
422
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000423/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000424 * *
425 * Utilities *
426 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000427 ************************************************************************/
428
429/**
430 * xsltPointerList:
431 *
432 * Pointer-list for various purposes.
433 */
434typedef struct _xmlPointerList xmlPointerList;
435typedef xmlPointerList *xmlPointerListPtr;
436struct _xmlPointerList {
437 void **items;
438 int number;
439 int size;
440};
441/*
442* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
443* and here, we should make the functions public.
444*/
445static int
Daniel Veillard45490ae2008-07-29 09:13:19 +0000446xmlPointerListAddSize(xmlPointerListPtr list,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000447 void *item,
448 int initialSize)
449{
450 if (list->items == NULL) {
451 if (initialSize <= 0)
452 initialSize = 1;
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800453 list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000454 if (list->items == NULL) {
455 xmlXPathErrMemory(NULL,
456 "xmlPointerListCreate: allocating item\n");
457 return(-1);
458 }
459 list->number = 0;
460 list->size = initialSize;
461 } else if (list->size <= list->number) {
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800462 if (list->size > 50000000) {
463 xmlXPathErrMemory(NULL,
464 "xmlPointerListAddSize: re-allocating item\n");
465 return(-1);
466 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000467 list->size *= 2;
468 list->items = (void **) xmlRealloc(list->items,
469 list->size * sizeof(void *));
470 if (list->items == NULL) {
471 xmlXPathErrMemory(NULL,
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800472 "xmlPointerListAddSize: re-allocating item\n");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000473 list->size = 0;
474 return(-1);
475 }
476 }
477 list->items[list->number++] = item;
478 return(0);
479}
480
481/**
482 * xsltPointerListCreate:
483 *
484 * Creates an xsltPointerList structure.
485 *
486 * Returns a xsltPointerList structure or NULL in case of an error.
487 */
488static xmlPointerListPtr
489xmlPointerListCreate(int initialSize)
490{
491 xmlPointerListPtr ret;
492
493 ret = xmlMalloc(sizeof(xmlPointerList));
494 if (ret == NULL) {
495 xmlXPathErrMemory(NULL,
496 "xmlPointerListCreate: allocating item\n");
497 return (NULL);
498 }
499 memset(ret, 0, sizeof(xmlPointerList));
500 if (initialSize > 0) {
501 xmlPointerListAddSize(ret, NULL, initialSize);
502 ret->number = 0;
503 }
504 return (ret);
505}
506
507/**
508 * xsltPointerListFree:
509 *
510 * Frees the xsltPointerList structure. This does not free
511 * the content of the list.
512 */
513static void
514xmlPointerListFree(xmlPointerListPtr list)
515{
516 if (list == NULL)
517 return;
518 if (list->items != NULL)
519 xmlFree(list->items);
520 xmlFree(list);
521}
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000522
523/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000524 * *
525 * Parser Types *
526 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000527 ************************************************************************/
528
529/*
530 * Types are private:
531 */
532
533typedef enum {
534 XPATH_OP_END=0,
535 XPATH_OP_AND,
536 XPATH_OP_OR,
537 XPATH_OP_EQUAL,
538 XPATH_OP_CMP,
539 XPATH_OP_PLUS,
540 XPATH_OP_MULT,
541 XPATH_OP_UNION,
542 XPATH_OP_ROOT,
543 XPATH_OP_NODE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000544 XPATH_OP_RESET, /* 10 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000545 XPATH_OP_COLLECT,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000546 XPATH_OP_VALUE, /* 12 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000547 XPATH_OP_VARIABLE,
548 XPATH_OP_FUNCTION,
549 XPATH_OP_ARG,
550 XPATH_OP_PREDICATE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000551 XPATH_OP_FILTER, /* 17 */
552 XPATH_OP_SORT /* 18 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000553#ifdef LIBXML_XPTR_ENABLED
554 ,XPATH_OP_RANGETO
555#endif
556} xmlXPathOp;
557
558typedef enum {
559 AXIS_ANCESTOR = 1,
560 AXIS_ANCESTOR_OR_SELF,
561 AXIS_ATTRIBUTE,
562 AXIS_CHILD,
563 AXIS_DESCENDANT,
564 AXIS_DESCENDANT_OR_SELF,
565 AXIS_FOLLOWING,
566 AXIS_FOLLOWING_SIBLING,
567 AXIS_NAMESPACE,
568 AXIS_PARENT,
569 AXIS_PRECEDING,
570 AXIS_PRECEDING_SIBLING,
Daniel Veillard45490ae2008-07-29 09:13:19 +0000571 AXIS_SELF
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000572} xmlXPathAxisVal;
573
574typedef enum {
575 NODE_TEST_NONE = 0,
576 NODE_TEST_TYPE = 1,
577 NODE_TEST_PI = 2,
578 NODE_TEST_ALL = 3,
579 NODE_TEST_NS = 4,
580 NODE_TEST_NAME = 5
581} xmlXPathTestVal;
582
583typedef enum {
584 NODE_TYPE_NODE = 0,
585 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
586 NODE_TYPE_TEXT = XML_TEXT_NODE,
Daniel Veillard45490ae2008-07-29 09:13:19 +0000587 NODE_TYPE_PI = XML_PI_NODE
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000588} xmlXPathTypeVal;
589
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +0000590#define XP_REWRITE_DOS_CHILD_ELEM 1
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000591
592typedef struct _xmlXPathStepOp xmlXPathStepOp;
593typedef xmlXPathStepOp *xmlXPathStepOpPtr;
594struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000595 xmlXPathOp op; /* The identifier of the operation */
596 int ch1; /* First child */
597 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000598 int value;
599 int value2;
600 int value3;
601 void *value4;
602 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000603 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000604 void *cacheURI;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +0000605 int rewriteType;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000606};
607
608struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000609 int nbStep; /* Number of steps in this expression */
610 int maxStep; /* Maximum number of steps allocated */
611 xmlXPathStepOp *steps; /* ops for computation of this expression */
612 int last; /* index of last step in expression */
613 xmlChar *expr; /* the expression being computed */
Daniel Veillard4773df22004-01-23 13:15:13 +0000614 xmlDictPtr dict; /* the dictionnary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000615#ifdef DEBUG_EVAL_COUNTS
616 int nb;
617 xmlChar *string;
618#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000619#ifdef XPATH_STREAMING
620 xmlPatternPtr stream;
621#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000622};
623
624/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000625 * *
626 * Forward declarations *
627 * *
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000628 ************************************************************************/
629static void
630xmlXPathFreeValueTree(xmlNodeSetPtr obj);
631static void
632xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
633static int
634xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
635 xmlXPathStepOpPtr op, xmlNodePtr *first);
636static int
637xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +0000638 xmlXPathStepOpPtr op,
639 int isPredicate);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000640
641/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000642 * *
643 * Parser Type functions *
644 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000645 ************************************************************************/
646
647/**
648 * xmlXPathNewCompExpr:
649 *
650 * Create a new Xpath component
651 *
652 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
653 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000654static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000655xmlXPathNewCompExpr(void) {
656 xmlXPathCompExprPtr cur;
657
658 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
659 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000660 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000661 return(NULL);
662 }
663 memset(cur, 0, sizeof(xmlXPathCompExpr));
664 cur->maxStep = 10;
665 cur->nbStep = 0;
666 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
667 sizeof(xmlXPathStepOp));
668 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000669 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000670 xmlFree(cur);
671 return(NULL);
672 }
673 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
674 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000675#ifdef DEBUG_EVAL_COUNTS
676 cur->nb = 0;
677#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000678 return(cur);
679}
680
681/**
682 * xmlXPathFreeCompExpr:
683 * @comp: an XPATH comp
684 *
685 * Free up the memory allocated by @comp
686 */
687void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000688xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
689{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000690 xmlXPathStepOpPtr op;
691 int i;
692
693 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000694 return;
Daniel Veillard4773df22004-01-23 13:15:13 +0000695 if (comp->dict == NULL) {
696 for (i = 0; i < comp->nbStep; i++) {
697 op = &comp->steps[i];
698 if (op->value4 != NULL) {
699 if (op->op == XPATH_OP_VALUE)
700 xmlXPathFreeObject(op->value4);
701 else
702 xmlFree(op->value4);
703 }
704 if (op->value5 != NULL)
705 xmlFree(op->value5);
706 }
707 } else {
708 for (i = 0; i < comp->nbStep; i++) {
709 op = &comp->steps[i];
710 if (op->value4 != NULL) {
711 if (op->op == XPATH_OP_VALUE)
712 xmlXPathFreeObject(op->value4);
713 }
714 }
715 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000716 }
717 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000718 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000719 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000720#ifdef DEBUG_EVAL_COUNTS
721 if (comp->string != NULL) {
722 xmlFree(comp->string);
723 }
724#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000725#ifdef XPATH_STREAMING
726 if (comp->stream != NULL) {
727 xmlFreePatternList(comp->stream);
728 }
729#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000730 if (comp->expr != NULL) {
731 xmlFree(comp->expr);
732 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000733
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000734 xmlFree(comp);
735}
736
737/**
738 * xmlXPathCompExprAdd:
739 * @comp: the compiled expression
740 * @ch1: first child index
741 * @ch2: second child index
742 * @op: an op
743 * @value: the first int value
744 * @value2: the second int value
745 * @value3: the third int value
746 * @value4: the first string value
747 * @value5: the second string value
748 *
William M. Brack08171912003-12-29 02:52:11 +0000749 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000750 *
751 * Returns -1 in case of failure, the index otherwise
752 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000753static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000754xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
755 xmlXPathOp op, int value,
756 int value2, int value3, void *value4, void *value5) {
757 if (comp->nbStep >= comp->maxStep) {
758 xmlXPathStepOp *real;
759
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800760 if (comp->maxStep >= XPATH_MAX_STEPS) {
761 xmlXPathErrMemory(NULL, "adding step\n");
762 return(-1);
763 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000764 comp->maxStep *= 2;
765 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
766 comp->maxStep * sizeof(xmlXPathStepOp));
767 if (real == NULL) {
768 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000769 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000770 return(-1);
771 }
772 comp->steps = real;
773 }
774 comp->last = comp->nbStep;
Kasimier T. Buchcik6422d912006-06-26 14:31:53 +0000775 comp->steps[comp->nbStep].rewriteType = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000776 comp->steps[comp->nbStep].ch1 = ch1;
777 comp->steps[comp->nbStep].ch2 = ch2;
778 comp->steps[comp->nbStep].op = op;
779 comp->steps[comp->nbStep].value = value;
780 comp->steps[comp->nbStep].value2 = value2;
781 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +0000782 if ((comp->dict != NULL) &&
783 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
784 (op == XPATH_OP_COLLECT))) {
785 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000786 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000787 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000788 xmlFree(value4);
789 } else
790 comp->steps[comp->nbStep].value4 = NULL;
791 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000792 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000793 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000794 xmlFree(value5);
795 } else
796 comp->steps[comp->nbStep].value5 = NULL;
797 } else {
798 comp->steps[comp->nbStep].value4 = value4;
799 comp->steps[comp->nbStep].value5 = value5;
800 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000801 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000802 return(comp->nbStep++);
803}
804
Daniel Veillardf06307e2001-07-03 10:35:50 +0000805/**
806 * xmlXPathCompSwap:
807 * @comp: the compiled expression
808 * @op: operation index
809 *
810 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000811 */
812static void
813xmlXPathCompSwap(xmlXPathStepOpPtr op) {
814 int tmp;
815
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000816#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000817 /*
818 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +0000819 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +0000820 * application
821 */
822 if (xmlXPathDisableOptimizer)
823 return;
824#endif
825
Daniel Veillardf06307e2001-07-03 10:35:50 +0000826 tmp = op->ch1;
827 op->ch1 = op->ch2;
828 op->ch2 = tmp;
829}
830
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000831#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
832 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
833 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000834#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
835 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
836 (op), (val), (val2), (val3), (val4), (val5))
837
Daniel Veillard45490ae2008-07-29 09:13:19 +0000838#define PUSH_LEAVE_EXPR(op, val, val2) \
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000839xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
840
Daniel Veillard45490ae2008-07-29 09:13:19 +0000841#define PUSH_UNARY_EXPR(op, ch, val, val2) \
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000842xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
843
Daniel Veillard45490ae2008-07-29 09:13:19 +0000844#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +0000845xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
846 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000847
848/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000849 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +0000850 * XPath object cache structures *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000851 * *
852 ************************************************************************/
853
854/* #define XP_DEFAULT_CACHE_ON */
855
Kasimier T. Buchcik58694692006-05-31 12:37:28 +0000856#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000857
Kasimier T. Buchcik58694692006-05-31 12:37:28 +0000858typedef struct _xmlXPathContextCache xmlXPathContextCache;
859typedef xmlXPathContextCache *xmlXPathContextCachePtr;
860struct _xmlXPathContextCache {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +0000861 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
862 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
863 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
864 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
865 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000866 int maxNodeset;
867 int maxString;
868 int maxBoolean;
869 int maxNumber;
870 int maxMisc;
871#ifdef XP_DEBUG_OBJ_USAGE
872 int dbgCachedAll;
873 int dbgCachedNodeset;
874 int dbgCachedString;
875 int dbgCachedBool;
876 int dbgCachedNumber;
877 int dbgCachedPoint;
878 int dbgCachedRange;
879 int dbgCachedLocset;
880 int dbgCachedUsers;
881 int dbgCachedXSLTTree;
Daniel Veillard45490ae2008-07-29 09:13:19 +0000882 int dbgCachedUndefined;
883
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000884
885 int dbgReusedAll;
886 int dbgReusedNodeset;
887 int dbgReusedString;
888 int dbgReusedBool;
889 int dbgReusedNumber;
890 int dbgReusedPoint;
891 int dbgReusedRange;
892 int dbgReusedLocset;
893 int dbgReusedUsers;
894 int dbgReusedXSLTTree;
895 int dbgReusedUndefined;
896
897#endif
898};
899
900/************************************************************************
901 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +0000902 * Debugging related functions *
Owen Taylor3473f882001-02-23 17:55:21 +0000903 * *
904 ************************************************************************/
905
Daniel Veillard45490ae2008-07-29 09:13:19 +0000906#define STRANGE \
Owen Taylor3473f882001-02-23 17:55:21 +0000907 xmlGenericError(xmlGenericErrorContext, \
908 "Internal error at %s:%d\n", \
909 __FILE__, __LINE__);
910
911#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000912static void
913xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000914 int i;
915 char shift[100];
916
917 for (i = 0;((i < depth) && (i < 25));i++)
918 shift[2 * i] = shift[2 * i + 1] = ' ';
919 shift[2 * i] = shift[2 * i + 1] = 0;
920 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200921 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +0000922 fprintf(output, "Node is NULL !\n");
923 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +0000924
Owen Taylor3473f882001-02-23 17:55:21 +0000925 }
926
927 if ((cur->type == XML_DOCUMENT_NODE) ||
928 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200929 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +0000930 fprintf(output, " /\n");
931 } else if (cur->type == XML_ATTRIBUTE_NODE)
932 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
933 else
934 xmlDebugDumpOneNode(output, cur, depth);
935}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000936static void
937xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000938 xmlNodePtr tmp;
939 int i;
940 char shift[100];
941
942 for (i = 0;((i < depth) && (i < 25));i++)
943 shift[2 * i] = shift[2 * i + 1] = ' ';
944 shift[2 * i] = shift[2 * i + 1] = 0;
945 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200946 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000947 fprintf(output, "Node is NULL !\n");
948 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +0000949
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000950 }
951
952 while (cur != NULL) {
953 tmp = cur;
954 cur = cur->next;
955 xmlDebugDumpOneNode(output, tmp, depth);
956 }
957}
Owen Taylor3473f882001-02-23 17:55:21 +0000958
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000959static void
960xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000961 int i;
962 char shift[100];
963
964 for (i = 0;((i < depth) && (i < 25));i++)
965 shift[2 * i] = shift[2 * i + 1] = ' ';
966 shift[2 * i] = shift[2 * i + 1] = 0;
967
968 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200969 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +0000970 fprintf(output, "NodeSet is NULL !\n");
971 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +0000972
Owen Taylor3473f882001-02-23 17:55:21 +0000973 }
974
Daniel Veillard911f49a2001-04-07 15:39:35 +0000975 if (cur != NULL) {
976 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
977 for (i = 0;i < cur->nodeNr;i++) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200978 fprintf(output, "%s", shift);
Daniel Veillard911f49a2001-04-07 15:39:35 +0000979 fprintf(output, "%d", i + 1);
980 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
981 }
Owen Taylor3473f882001-02-23 17:55:21 +0000982 }
983}
984
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000985static void
986xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000987 int i;
988 char shift[100];
989
990 for (i = 0;((i < depth) && (i < 25));i++)
991 shift[2 * i] = shift[2 * i + 1] = ' ';
992 shift[2 * i] = shift[2 * i + 1] = 0;
993
994 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200995 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000996 fprintf(output, "Value Tree is NULL !\n");
997 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +0000998
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000999 }
1000
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001001 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001002 fprintf(output, "%d", i + 1);
1003 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1004}
Owen Taylor3473f882001-02-23 17:55:21 +00001005#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001006static void
1007xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001008 int i;
1009 char shift[100];
1010
1011 for (i = 0;((i < depth) && (i < 25));i++)
1012 shift[2 * i] = shift[2 * i + 1] = ' ';
1013 shift[2 * i] = shift[2 * i + 1] = 0;
1014
1015 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001016 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001017 fprintf(output, "LocationSet is NULL !\n");
1018 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001019
Owen Taylor3473f882001-02-23 17:55:21 +00001020 }
1021
1022 for (i = 0;i < cur->locNr;i++) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001023 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001024 fprintf(output, "%d : ", i + 1);
1025 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1026 }
1027}
Daniel Veillard017b1082001-06-21 11:20:21 +00001028#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001029
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00001030/**
1031 * xmlXPathDebugDumpObject:
1032 * @output: the FILE * to dump the output
1033 * @cur: the object to inspect
1034 * @depth: indentation level
1035 *
1036 * Dump the content of the object for debugging purposes
1037 */
1038void
1039xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001040 int i;
1041 char shift[100];
1042
Daniel Veillarda82b1822004-11-08 16:24:57 +00001043 if (output == NULL) return;
1044
Owen Taylor3473f882001-02-23 17:55:21 +00001045 for (i = 0;((i < depth) && (i < 25));i++)
1046 shift[2 * i] = shift[2 * i + 1] = ' ';
1047 shift[2 * i] = shift[2 * i + 1] = 0;
1048
Kasimier T. Buchcik97258712006-01-05 12:30:43 +00001049
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001050 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001051
1052 if (cur == NULL) {
1053 fprintf(output, "Object is empty (NULL)\n");
1054 return;
1055 }
1056 switch(cur->type) {
1057 case XPATH_UNDEFINED:
1058 fprintf(output, "Object is uninitialized\n");
1059 break;
1060 case XPATH_NODESET:
1061 fprintf(output, "Object is a Node Set :\n");
1062 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1063 break;
1064 case XPATH_XSLT_TREE:
1065 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001066 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +00001067 break;
1068 case XPATH_BOOLEAN:
1069 fprintf(output, "Object is a Boolean : ");
1070 if (cur->boolval) fprintf(output, "true\n");
1071 else fprintf(output, "false\n");
1072 break;
1073 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +00001074 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001075 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001076 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001077 break;
1078 case -1:
1079 fprintf(output, "Object is a number : -Infinity\n");
1080 break;
1081 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001082 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001083 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001084 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1085 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001086 } else {
1087 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1088 }
1089 }
Owen Taylor3473f882001-02-23 17:55:21 +00001090 break;
1091 case XPATH_STRING:
1092 fprintf(output, "Object is a string : ");
1093 xmlDebugDumpString(output, cur->stringval);
1094 fprintf(output, "\n");
1095 break;
1096 case XPATH_POINT:
1097 fprintf(output, "Object is a point : index %d in node", cur->index);
1098 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1099 fprintf(output, "\n");
1100 break;
1101 case XPATH_RANGE:
1102 if ((cur->user2 == NULL) ||
1103 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1104 fprintf(output, "Object is a collapsed range :\n");
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001105 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001106 if (cur->index >= 0)
1107 fprintf(output, "index %d in ", cur->index);
1108 fprintf(output, "node\n");
1109 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1110 depth + 1);
1111 } else {
1112 fprintf(output, "Object is a range :\n");
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001113 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001114 fprintf(output, "From ");
1115 if (cur->index >= 0)
1116 fprintf(output, "index %d in ", cur->index);
1117 fprintf(output, "node\n");
1118 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1119 depth + 1);
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001120 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001121 fprintf(output, "To ");
1122 if (cur->index2 >= 0)
1123 fprintf(output, "index %d in ", cur->index2);
1124 fprintf(output, "node\n");
1125 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1126 depth + 1);
1127 fprintf(output, "\n");
1128 }
1129 break;
1130 case XPATH_LOCATIONSET:
1131#if defined(LIBXML_XPTR_ENABLED)
1132 fprintf(output, "Object is a Location Set:\n");
1133 xmlXPathDebugDumpLocationSet(output,
1134 (xmlLocationSetPtr) cur->user, depth);
1135#endif
1136 break;
1137 case XPATH_USERS:
1138 fprintf(output, "Object is user defined\n");
1139 break;
1140 }
1141}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001142
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001143static void
1144xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001145 xmlXPathStepOpPtr op, int depth) {
1146 int i;
1147 char shift[100];
1148
1149 for (i = 0;((i < depth) && (i < 25));i++)
1150 shift[2 * i] = shift[2 * i + 1] = ' ';
1151 shift[2 * i] = shift[2 * i + 1] = 0;
1152
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001153 fprintf(output, "%s", shift);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001154 if (op == NULL) {
1155 fprintf(output, "Step is NULL\n");
1156 return;
1157 }
1158 switch (op->op) {
1159 case XPATH_OP_END:
1160 fprintf(output, "END"); break;
1161 case XPATH_OP_AND:
1162 fprintf(output, "AND"); break;
1163 case XPATH_OP_OR:
1164 fprintf(output, "OR"); break;
1165 case XPATH_OP_EQUAL:
1166 if (op->value)
1167 fprintf(output, "EQUAL =");
1168 else
1169 fprintf(output, "EQUAL !=");
1170 break;
1171 case XPATH_OP_CMP:
1172 if (op->value)
1173 fprintf(output, "CMP <");
1174 else
1175 fprintf(output, "CMP >");
1176 if (!op->value2)
1177 fprintf(output, "=");
1178 break;
1179 case XPATH_OP_PLUS:
1180 if (op->value == 0)
1181 fprintf(output, "PLUS -");
1182 else if (op->value == 1)
1183 fprintf(output, "PLUS +");
1184 else if (op->value == 2)
1185 fprintf(output, "PLUS unary -");
1186 else if (op->value == 3)
1187 fprintf(output, "PLUS unary - -");
1188 break;
1189 case XPATH_OP_MULT:
1190 if (op->value == 0)
1191 fprintf(output, "MULT *");
1192 else if (op->value == 1)
1193 fprintf(output, "MULT div");
1194 else
1195 fprintf(output, "MULT mod");
1196 break;
1197 case XPATH_OP_UNION:
1198 fprintf(output, "UNION"); break;
1199 case XPATH_OP_ROOT:
1200 fprintf(output, "ROOT"); break;
1201 case XPATH_OP_NODE:
1202 fprintf(output, "NODE"); break;
1203 case XPATH_OP_RESET:
1204 fprintf(output, "RESET"); break;
1205 case XPATH_OP_SORT:
1206 fprintf(output, "SORT"); break;
1207 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +00001208 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1209 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1210 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001211 const xmlChar *prefix = op->value4;
1212 const xmlChar *name = op->value5;
1213
1214 fprintf(output, "COLLECT ");
1215 switch (axis) {
1216 case AXIS_ANCESTOR:
1217 fprintf(output, " 'ancestors' "); break;
1218 case AXIS_ANCESTOR_OR_SELF:
1219 fprintf(output, " 'ancestors-or-self' "); break;
1220 case AXIS_ATTRIBUTE:
1221 fprintf(output, " 'attributes' "); break;
1222 case AXIS_CHILD:
1223 fprintf(output, " 'child' "); break;
1224 case AXIS_DESCENDANT:
1225 fprintf(output, " 'descendant' "); break;
1226 case AXIS_DESCENDANT_OR_SELF:
1227 fprintf(output, " 'descendant-or-self' "); break;
1228 case AXIS_FOLLOWING:
1229 fprintf(output, " 'following' "); break;
1230 case AXIS_FOLLOWING_SIBLING:
1231 fprintf(output, " 'following-siblings' "); break;
1232 case AXIS_NAMESPACE:
1233 fprintf(output, " 'namespace' "); break;
1234 case AXIS_PARENT:
1235 fprintf(output, " 'parent' "); break;
1236 case AXIS_PRECEDING:
1237 fprintf(output, " 'preceding' "); break;
1238 case AXIS_PRECEDING_SIBLING:
1239 fprintf(output, " 'preceding-sibling' "); break;
1240 case AXIS_SELF:
1241 fprintf(output, " 'self' "); break;
1242 }
1243 switch (test) {
1244 case NODE_TEST_NONE:
1245 fprintf(output, "'none' "); break;
1246 case NODE_TEST_TYPE:
1247 fprintf(output, "'type' "); break;
1248 case NODE_TEST_PI:
1249 fprintf(output, "'PI' "); break;
1250 case NODE_TEST_ALL:
1251 fprintf(output, "'all' "); break;
1252 case NODE_TEST_NS:
1253 fprintf(output, "'namespace' "); break;
1254 case NODE_TEST_NAME:
1255 fprintf(output, "'name' "); break;
1256 }
1257 switch (type) {
1258 case NODE_TYPE_NODE:
1259 fprintf(output, "'node' "); break;
1260 case NODE_TYPE_COMMENT:
1261 fprintf(output, "'comment' "); break;
1262 case NODE_TYPE_TEXT:
1263 fprintf(output, "'text' "); break;
1264 case NODE_TYPE_PI:
1265 fprintf(output, "'PI' "); break;
1266 }
1267 if (prefix != NULL)
1268 fprintf(output, "%s:", prefix);
1269 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001270 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001271 break;
1272
1273 }
1274 case XPATH_OP_VALUE: {
1275 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1276
1277 fprintf(output, "ELEM ");
1278 xmlXPathDebugDumpObject(output, object, 0);
1279 goto finish;
1280 }
1281 case XPATH_OP_VARIABLE: {
1282 const xmlChar *prefix = op->value5;
1283 const xmlChar *name = op->value4;
1284
1285 if (prefix != NULL)
1286 fprintf(output, "VARIABLE %s:%s", prefix, name);
1287 else
1288 fprintf(output, "VARIABLE %s", name);
1289 break;
1290 }
1291 case XPATH_OP_FUNCTION: {
1292 int nbargs = op->value;
1293 const xmlChar *prefix = op->value5;
1294 const xmlChar *name = op->value4;
1295
1296 if (prefix != NULL)
1297 fprintf(output, "FUNCTION %s:%s(%d args)",
1298 prefix, name, nbargs);
1299 else
1300 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1301 break;
1302 }
1303 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1304 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001305 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001306#ifdef LIBXML_XPTR_ENABLED
1307 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1308#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001309 default:
1310 fprintf(output, "UNKNOWN %d\n", op->op); return;
1311 }
1312 fprintf(output, "\n");
1313finish:
1314 if (op->ch1 >= 0)
1315 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1316 if (op->ch2 >= 0)
1317 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1318}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001319
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001320/**
1321 * xmlXPathDebugDumpCompExpr:
1322 * @output: the FILE * for the output
1323 * @comp: the precompiled XPath expression
1324 * @depth: the indentation level.
1325 *
1326 * Dumps the tree of the compiled XPath expression.
1327 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001328void
1329xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1330 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001331 int i;
1332 char shift[100];
1333
Daniel Veillarda82b1822004-11-08 16:24:57 +00001334 if ((output == NULL) || (comp == NULL)) return;
1335
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001336 for (i = 0;((i < depth) && (i < 25));i++)
1337 shift[2 * i] = shift[2 * i + 1] = ' ';
1338 shift[2 * i] = shift[2 * i + 1] = 0;
1339
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001340 fprintf(output, "%s", shift);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001341
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001342 fprintf(output, "Compiled Expression : %d elements\n",
1343 comp->nbStep);
1344 i = comp->last;
1345 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1346}
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001347
1348#ifdef XP_DEBUG_OBJ_USAGE
1349
1350/*
1351* XPath object usage related debugging variables.
1352*/
1353static int xmlXPathDebugObjCounterUndefined = 0;
1354static int xmlXPathDebugObjCounterNodeset = 0;
1355static int xmlXPathDebugObjCounterBool = 0;
1356static int xmlXPathDebugObjCounterNumber = 0;
1357static int xmlXPathDebugObjCounterString = 0;
1358static int xmlXPathDebugObjCounterPoint = 0;
1359static int xmlXPathDebugObjCounterRange = 0;
1360static int xmlXPathDebugObjCounterLocset = 0;
1361static int xmlXPathDebugObjCounterUsers = 0;
1362static int xmlXPathDebugObjCounterXSLTTree = 0;
1363static int xmlXPathDebugObjCounterAll = 0;
1364
1365static int xmlXPathDebugObjTotalUndefined = 0;
1366static int xmlXPathDebugObjTotalNodeset = 0;
1367static int xmlXPathDebugObjTotalBool = 0;
1368static int xmlXPathDebugObjTotalNumber = 0;
1369static int xmlXPathDebugObjTotalString = 0;
1370static int xmlXPathDebugObjTotalPoint = 0;
1371static int xmlXPathDebugObjTotalRange = 0;
1372static int xmlXPathDebugObjTotalLocset = 0;
1373static int xmlXPathDebugObjTotalUsers = 0;
1374static int xmlXPathDebugObjTotalXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001375static int xmlXPathDebugObjTotalAll = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001376
1377static int xmlXPathDebugObjMaxUndefined = 0;
1378static int xmlXPathDebugObjMaxNodeset = 0;
1379static int xmlXPathDebugObjMaxBool = 0;
1380static int xmlXPathDebugObjMaxNumber = 0;
1381static int xmlXPathDebugObjMaxString = 0;
1382static int xmlXPathDebugObjMaxPoint = 0;
1383static int xmlXPathDebugObjMaxRange = 0;
1384static int xmlXPathDebugObjMaxLocset = 0;
1385static int xmlXPathDebugObjMaxUsers = 0;
1386static int xmlXPathDebugObjMaxXSLTTree = 0;
1387static int xmlXPathDebugObjMaxAll = 0;
1388
1389/* REVISIT TODO: Make this static when committing */
1390static void
1391xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1392{
1393 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001394 if (ctxt->cache != NULL) {
1395 xmlXPathContextCachePtr cache =
1396 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001397
1398 cache->dbgCachedAll = 0;
1399 cache->dbgCachedNodeset = 0;
1400 cache->dbgCachedString = 0;
1401 cache->dbgCachedBool = 0;
1402 cache->dbgCachedNumber = 0;
1403 cache->dbgCachedPoint = 0;
1404 cache->dbgCachedRange = 0;
1405 cache->dbgCachedLocset = 0;
1406 cache->dbgCachedUsers = 0;
1407 cache->dbgCachedXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001408 cache->dbgCachedUndefined = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001409
1410 cache->dbgReusedAll = 0;
1411 cache->dbgReusedNodeset = 0;
1412 cache->dbgReusedString = 0;
1413 cache->dbgReusedBool = 0;
1414 cache->dbgReusedNumber = 0;
1415 cache->dbgReusedPoint = 0;
1416 cache->dbgReusedRange = 0;
1417 cache->dbgReusedLocset = 0;
1418 cache->dbgReusedUsers = 0;
1419 cache->dbgReusedXSLTTree = 0;
1420 cache->dbgReusedUndefined = 0;
1421 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00001422 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001423
1424 xmlXPathDebugObjCounterUndefined = 0;
1425 xmlXPathDebugObjCounterNodeset = 0;
1426 xmlXPathDebugObjCounterBool = 0;
1427 xmlXPathDebugObjCounterNumber = 0;
1428 xmlXPathDebugObjCounterString = 0;
1429 xmlXPathDebugObjCounterPoint = 0;
1430 xmlXPathDebugObjCounterRange = 0;
1431 xmlXPathDebugObjCounterLocset = 0;
1432 xmlXPathDebugObjCounterUsers = 0;
1433 xmlXPathDebugObjCounterXSLTTree = 0;
1434 xmlXPathDebugObjCounterAll = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001435
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001436 xmlXPathDebugObjTotalUndefined = 0;
1437 xmlXPathDebugObjTotalNodeset = 0;
1438 xmlXPathDebugObjTotalBool = 0;
1439 xmlXPathDebugObjTotalNumber = 0;
1440 xmlXPathDebugObjTotalString = 0;
1441 xmlXPathDebugObjTotalPoint = 0;
1442 xmlXPathDebugObjTotalRange = 0;
1443 xmlXPathDebugObjTotalLocset = 0;
1444 xmlXPathDebugObjTotalUsers = 0;
1445 xmlXPathDebugObjTotalXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001446 xmlXPathDebugObjTotalAll = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001447
1448 xmlXPathDebugObjMaxUndefined = 0;
1449 xmlXPathDebugObjMaxNodeset = 0;
1450 xmlXPathDebugObjMaxBool = 0;
1451 xmlXPathDebugObjMaxNumber = 0;
1452 xmlXPathDebugObjMaxString = 0;
1453 xmlXPathDebugObjMaxPoint = 0;
1454 xmlXPathDebugObjMaxRange = 0;
1455 xmlXPathDebugObjMaxLocset = 0;
1456 xmlXPathDebugObjMaxUsers = 0;
1457 xmlXPathDebugObjMaxXSLTTree = 0;
1458 xmlXPathDebugObjMaxAll = 0;
1459
1460}
1461
1462static void
1463xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1464 xmlXPathObjectType objType)
1465{
1466 int isCached = 0;
1467
1468 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001469 if (ctxt->cache != NULL) {
1470 xmlXPathContextCachePtr cache =
1471 (xmlXPathContextCachePtr) ctxt->cache;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001472
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001473 isCached = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001474
1475 cache->dbgReusedAll++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001476 switch (objType) {
1477 case XPATH_UNDEFINED:
1478 cache->dbgReusedUndefined++;
1479 break;
1480 case XPATH_NODESET:
1481 cache->dbgReusedNodeset++;
1482 break;
1483 case XPATH_BOOLEAN:
1484 cache->dbgReusedBool++;
1485 break;
1486 case XPATH_NUMBER:
1487 cache->dbgReusedNumber++;
1488 break;
1489 case XPATH_STRING:
1490 cache->dbgReusedString++;
1491 break;
1492 case XPATH_POINT:
1493 cache->dbgReusedPoint++;
1494 break;
1495 case XPATH_RANGE:
1496 cache->dbgReusedRange++;
1497 break;
1498 case XPATH_LOCATIONSET:
1499 cache->dbgReusedLocset++;
1500 break;
1501 case XPATH_USERS:
1502 cache->dbgReusedUsers++;
1503 break;
1504 case XPATH_XSLT_TREE:
1505 cache->dbgReusedXSLTTree++;
1506 break;
1507 default:
1508 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001509 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001510 }
1511 }
1512
1513 switch (objType) {
1514 case XPATH_UNDEFINED:
1515 if (! isCached)
1516 xmlXPathDebugObjTotalUndefined++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001517 xmlXPathDebugObjCounterUndefined++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001518 if (xmlXPathDebugObjCounterUndefined >
1519 xmlXPathDebugObjMaxUndefined)
1520 xmlXPathDebugObjMaxUndefined =
1521 xmlXPathDebugObjCounterUndefined;
1522 break;
1523 case XPATH_NODESET:
1524 if (! isCached)
1525 xmlXPathDebugObjTotalNodeset++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001526 xmlXPathDebugObjCounterNodeset++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001527 if (xmlXPathDebugObjCounterNodeset >
1528 xmlXPathDebugObjMaxNodeset)
1529 xmlXPathDebugObjMaxNodeset =
1530 xmlXPathDebugObjCounterNodeset;
1531 break;
1532 case XPATH_BOOLEAN:
1533 if (! isCached)
1534 xmlXPathDebugObjTotalBool++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001535 xmlXPathDebugObjCounterBool++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001536 if (xmlXPathDebugObjCounterBool >
1537 xmlXPathDebugObjMaxBool)
1538 xmlXPathDebugObjMaxBool =
1539 xmlXPathDebugObjCounterBool;
1540 break;
1541 case XPATH_NUMBER:
1542 if (! isCached)
1543 xmlXPathDebugObjTotalNumber++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001544 xmlXPathDebugObjCounterNumber++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001545 if (xmlXPathDebugObjCounterNumber >
1546 xmlXPathDebugObjMaxNumber)
1547 xmlXPathDebugObjMaxNumber =
1548 xmlXPathDebugObjCounterNumber;
1549 break;
1550 case XPATH_STRING:
1551 if (! isCached)
1552 xmlXPathDebugObjTotalString++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001553 xmlXPathDebugObjCounterString++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001554 if (xmlXPathDebugObjCounterString >
1555 xmlXPathDebugObjMaxString)
1556 xmlXPathDebugObjMaxString =
1557 xmlXPathDebugObjCounterString;
1558 break;
1559 case XPATH_POINT:
1560 if (! isCached)
1561 xmlXPathDebugObjTotalPoint++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001562 xmlXPathDebugObjCounterPoint++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001563 if (xmlXPathDebugObjCounterPoint >
1564 xmlXPathDebugObjMaxPoint)
1565 xmlXPathDebugObjMaxPoint =
1566 xmlXPathDebugObjCounterPoint;
1567 break;
1568 case XPATH_RANGE:
1569 if (! isCached)
1570 xmlXPathDebugObjTotalRange++;
1571 xmlXPathDebugObjCounterRange++;
1572 if (xmlXPathDebugObjCounterRange >
1573 xmlXPathDebugObjMaxRange)
1574 xmlXPathDebugObjMaxRange =
1575 xmlXPathDebugObjCounterRange;
1576 break;
1577 case XPATH_LOCATIONSET:
1578 if (! isCached)
1579 xmlXPathDebugObjTotalLocset++;
1580 xmlXPathDebugObjCounterLocset++;
1581 if (xmlXPathDebugObjCounterLocset >
1582 xmlXPathDebugObjMaxLocset)
1583 xmlXPathDebugObjMaxLocset =
1584 xmlXPathDebugObjCounterLocset;
1585 break;
1586 case XPATH_USERS:
1587 if (! isCached)
1588 xmlXPathDebugObjTotalUsers++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001589 xmlXPathDebugObjCounterUsers++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001590 if (xmlXPathDebugObjCounterUsers >
1591 xmlXPathDebugObjMaxUsers)
1592 xmlXPathDebugObjMaxUsers =
1593 xmlXPathDebugObjCounterUsers;
1594 break;
1595 case XPATH_XSLT_TREE:
1596 if (! isCached)
1597 xmlXPathDebugObjTotalXSLTTree++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001598 xmlXPathDebugObjCounterXSLTTree++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001599 if (xmlXPathDebugObjCounterXSLTTree >
1600 xmlXPathDebugObjMaxXSLTTree)
1601 xmlXPathDebugObjMaxXSLTTree =
1602 xmlXPathDebugObjCounterXSLTTree;
1603 break;
1604 default:
1605 break;
1606 }
1607 if (! isCached)
1608 xmlXPathDebugObjTotalAll++;
1609 xmlXPathDebugObjCounterAll++;
1610 if (xmlXPathDebugObjCounterAll >
1611 xmlXPathDebugObjMaxAll)
1612 xmlXPathDebugObjMaxAll =
1613 xmlXPathDebugObjCounterAll;
1614}
1615
1616static void
1617xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1618 xmlXPathObjectType objType)
1619{
1620 int isCached = 0;
1621
1622 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001623 if (ctxt->cache != NULL) {
1624 xmlXPathContextCachePtr cache =
1625 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001626
Daniel Veillard45490ae2008-07-29 09:13:19 +00001627 isCached = 1;
1628
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001629 cache->dbgCachedAll++;
1630 switch (objType) {
1631 case XPATH_UNDEFINED:
1632 cache->dbgCachedUndefined++;
1633 break;
1634 case XPATH_NODESET:
1635 cache->dbgCachedNodeset++;
1636 break;
1637 case XPATH_BOOLEAN:
1638 cache->dbgCachedBool++;
1639 break;
1640 case XPATH_NUMBER:
1641 cache->dbgCachedNumber++;
1642 break;
1643 case XPATH_STRING:
1644 cache->dbgCachedString++;
1645 break;
1646 case XPATH_POINT:
1647 cache->dbgCachedPoint++;
1648 break;
1649 case XPATH_RANGE:
1650 cache->dbgCachedRange++;
1651 break;
1652 case XPATH_LOCATIONSET:
1653 cache->dbgCachedLocset++;
1654 break;
1655 case XPATH_USERS:
1656 cache->dbgCachedUsers++;
1657 break;
1658 case XPATH_XSLT_TREE:
1659 cache->dbgCachedXSLTTree++;
1660 break;
1661 default:
1662 break;
1663 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00001664
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001665 }
1666 }
1667 switch (objType) {
1668 case XPATH_UNDEFINED:
1669 xmlXPathDebugObjCounterUndefined--;
1670 break;
1671 case XPATH_NODESET:
1672 xmlXPathDebugObjCounterNodeset--;
1673 break;
1674 case XPATH_BOOLEAN:
1675 xmlXPathDebugObjCounterBool--;
1676 break;
1677 case XPATH_NUMBER:
1678 xmlXPathDebugObjCounterNumber--;
1679 break;
1680 case XPATH_STRING:
1681 xmlXPathDebugObjCounterString--;
1682 break;
1683 case XPATH_POINT:
1684 xmlXPathDebugObjCounterPoint--;
1685 break;
1686 case XPATH_RANGE:
1687 xmlXPathDebugObjCounterRange--;
1688 break;
1689 case XPATH_LOCATIONSET:
1690 xmlXPathDebugObjCounterLocset--;
1691 break;
1692 case XPATH_USERS:
1693 xmlXPathDebugObjCounterUsers--;
1694 break;
1695 case XPATH_XSLT_TREE:
1696 xmlXPathDebugObjCounterXSLTTree--;
1697 break;
1698 default:
1699 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001700 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001701 xmlXPathDebugObjCounterAll--;
1702}
1703
1704/* REVISIT TODO: Make this static when committing */
1705static void
1706xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
1707{
1708 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
1709 reqXSLTTree, reqUndefined;
1710 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
1711 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
1712 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
1713 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
1714 int leftObjs = xmlXPathDebugObjCounterAll;
1715
1716 reqAll = xmlXPathDebugObjTotalAll;
1717 reqNodeset = xmlXPathDebugObjTotalNodeset;
1718 reqString = xmlXPathDebugObjTotalString;
1719 reqBool = xmlXPathDebugObjTotalBool;
1720 reqNumber = xmlXPathDebugObjTotalNumber;
1721 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
1722 reqUndefined = xmlXPathDebugObjTotalUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001723
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001724 printf("# XPath object usage:\n");
1725
1726 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001727 if (ctxt->cache != NULL) {
1728 xmlXPathContextCachePtr cache =
1729 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001730
1731 reAll = cache->dbgReusedAll;
1732 reqAll += reAll;
1733 reNodeset = cache->dbgReusedNodeset;
1734 reqNodeset += reNodeset;
1735 reString = cache->dbgReusedString;
1736 reqString += reString;
1737 reBool = cache->dbgReusedBool;
1738 reqBool += reBool;
1739 reNumber = cache->dbgReusedNumber;
1740 reqNumber += reNumber;
1741 reXSLTTree = cache->dbgReusedXSLTTree;
1742 reqXSLTTree += reXSLTTree;
1743 reUndefined = cache->dbgReusedUndefined;
1744 reqUndefined += reUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001745
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001746 caAll = cache->dbgCachedAll;
1747 caBool = cache->dbgCachedBool;
1748 caNodeset = cache->dbgCachedNodeset;
1749 caString = cache->dbgCachedString;
1750 caNumber = cache->dbgCachedNumber;
1751 caXSLTTree = cache->dbgCachedXSLTTree;
1752 caUndefined = cache->dbgCachedUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001753
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001754 if (cache->nodesetObjs)
1755 leftObjs -= cache->nodesetObjs->number;
1756 if (cache->stringObjs)
1757 leftObjs -= cache->stringObjs->number;
1758 if (cache->booleanObjs)
1759 leftObjs -= cache->booleanObjs->number;
1760 if (cache->numberObjs)
1761 leftObjs -= cache->numberObjs->number;
1762 if (cache->miscObjs)
1763 leftObjs -= cache->miscObjs->number;
1764 }
1765 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00001766
1767 printf("# all\n");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001768 printf("# total : %d\n", reqAll);
1769 printf("# left : %d\n", leftObjs);
1770 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
1771 printf("# reused : %d\n", reAll);
1772 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
1773
1774 printf("# node-sets\n");
1775 printf("# total : %d\n", reqNodeset);
1776 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
1777 printf("# reused : %d\n", reNodeset);
1778 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
1779
1780 printf("# strings\n");
1781 printf("# total : %d\n", reqString);
1782 printf("# created: %d\n", xmlXPathDebugObjTotalString);
1783 printf("# reused : %d\n", reString);
1784 printf("# max : %d\n", xmlXPathDebugObjMaxString);
1785
1786 printf("# booleans\n");
1787 printf("# total : %d\n", reqBool);
1788 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
1789 printf("# reused : %d\n", reBool);
1790 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
1791
1792 printf("# numbers\n");
1793 printf("# total : %d\n", reqNumber);
1794 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
1795 printf("# reused : %d\n", reNumber);
1796 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
1797
1798 printf("# XSLT result tree fragments\n");
1799 printf("# total : %d\n", reqXSLTTree);
1800 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
1801 printf("# reused : %d\n", reXSLTTree);
1802 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
1803
1804 printf("# undefined\n");
1805 printf("# total : %d\n", reqUndefined);
1806 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
1807 printf("# reused : %d\n", reUndefined);
1808 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
1809
1810}
1811
1812#endif /* XP_DEBUG_OBJ_USAGE */
1813
Daniel Veillard017b1082001-06-21 11:20:21 +00001814#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001815
1816/************************************************************************
1817 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001818 * XPath object caching *
1819 * *
1820 ************************************************************************/
1821
1822/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001823 * xmlXPathNewCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001824 *
1825 * Create a new object cache
1826 *
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001827 * Returns the xmlXPathCache just allocated.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001828 */
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001829static xmlXPathContextCachePtr
1830xmlXPathNewCache(void)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001831{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001832 xmlXPathContextCachePtr ret;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001833
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001834 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001835 if (ret == NULL) {
1836 xmlXPathErrMemory(NULL, "creating object cache\n");
1837 return(NULL);
1838 }
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001839 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001840 ret->maxNodeset = 100;
1841 ret->maxString = 100;
1842 ret->maxBoolean = 100;
1843 ret->maxNumber = 100;
1844 ret->maxMisc = 100;
1845 return(ret);
1846}
1847
1848static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001849xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001850{
1851 int i;
1852 xmlXPathObjectPtr obj;
1853
1854 if (list == NULL)
1855 return;
1856
1857 for (i = 0; i < list->number; i++) {
1858 obj = list->items[i];
1859 /*
1860 * Note that it is already assured that we don't need to
1861 * look out for namespace nodes in the node-set.
1862 */
1863 if (obj->nodesetval != NULL) {
1864 if (obj->nodesetval->nodeTab != NULL)
1865 xmlFree(obj->nodesetval->nodeTab);
1866 xmlFree(obj->nodesetval);
1867 }
1868 xmlFree(obj);
1869#ifdef XP_DEBUG_OBJ_USAGE
1870 xmlXPathDebugObjCounterAll--;
1871#endif
1872 }
1873 xmlPointerListFree(list);
1874}
1875
1876static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001877xmlXPathFreeCache(xmlXPathContextCachePtr cache)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001878{
1879 if (cache == NULL)
1880 return;
1881 if (cache->nodesetObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001882 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001883 if (cache->stringObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001884 xmlXPathCacheFreeObjectList(cache->stringObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001885 if (cache->booleanObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001886 xmlXPathCacheFreeObjectList(cache->booleanObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001887 if (cache->numberObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001888 xmlXPathCacheFreeObjectList(cache->numberObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001889 if (cache->miscObjs)
Daniel Veillard45490ae2008-07-29 09:13:19 +00001890 xmlXPathCacheFreeObjectList(cache->miscObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001891 xmlFree(cache);
1892}
1893
1894/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001895 * xmlXPathContextSetCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001896 *
1897 * @ctxt: the XPath context
1898 * @active: enables/disables (creates/frees) the cache
Daniel Veillard45490ae2008-07-29 09:13:19 +00001899 * @value: a value with semantics dependant on @options
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001900 * @options: options (currently only the value 0 is used)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001901 *
1902 * Creates/frees an object cache on the XPath context.
1903 * If activates XPath objects (xmlXPathObject) will be cached internally
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001904 * to be reused.
1905 * @options:
1906 * 0: This will set the XPath object caching:
1907 * @value:
1908 * This will set the maximum number of XPath objects
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001909 * to be cached per slot
1910 * There are 5 slots for: node-set, string, number, boolean, and
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001911 * misc objects. Use <0 for the default number (100).
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001912 * Other values for @options have currently no effect.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001913 *
1914 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1915 */
1916int
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001917xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1918 int active,
1919 int value,
1920 int options)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001921{
1922 if (ctxt == NULL)
1923 return(-1);
1924 if (active) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001925 xmlXPathContextCachePtr cache;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001926
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001927 if (ctxt->cache == NULL) {
1928 ctxt->cache = xmlXPathNewCache();
1929 if (ctxt->cache == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001930 return(-1);
1931 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001932 cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001933 if (options == 0) {
1934 if (value < 0)
1935 value = 100;
1936 cache->maxNodeset = value;
1937 cache->maxString = value;
1938 cache->maxNumber = value;
1939 cache->maxBoolean = value;
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001940 cache->maxMisc = value;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001941 }
1942 } else if (ctxt->cache != NULL) {
1943 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1944 ctxt->cache = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001945 }
1946 return(0);
1947}
1948
1949/**
1950 * xmlXPathCacheWrapNodeSet:
1951 * @ctxt: the XPath context
1952 * @val: the NodePtr value
1953 *
1954 * This is the cached version of xmlXPathWrapNodeSet().
1955 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1956 *
1957 * Returns the created or reused object.
1958 */
1959static xmlXPathObjectPtr
1960xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00001961{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001962 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1963 xmlXPathContextCachePtr cache =
1964 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001965
1966 if ((cache->miscObjs != NULL) &&
1967 (cache->miscObjs->number != 0))
1968 {
1969 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001970
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001971 ret = (xmlXPathObjectPtr)
1972 cache->miscObjs->items[--cache->miscObjs->number];
1973 ret->type = XPATH_NODESET;
1974 ret->nodesetval = val;
1975#ifdef XP_DEBUG_OBJ_USAGE
1976 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
1977#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00001978 return(ret);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001979 }
1980 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00001981
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001982 return(xmlXPathWrapNodeSet(val));
Daniel Veillard45490ae2008-07-29 09:13:19 +00001983
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001984}
1985
1986/**
1987 * xmlXPathCacheWrapString:
1988 * @ctxt: the XPath context
1989 * @val: the xmlChar * value
1990 *
1991 * This is the cached version of xmlXPathWrapString().
1992 * Wraps the @val string into an XPath object.
1993 *
1994 * Returns the created or reused object.
1995 */
1996static xmlXPathObjectPtr
1997xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00001998{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001999 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2000 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002001
2002 if ((cache->stringObjs != NULL) &&
2003 (cache->stringObjs->number != 0))
2004 {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002005
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002006 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002007
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002008 ret = (xmlXPathObjectPtr)
2009 cache->stringObjs->items[--cache->stringObjs->number];
2010 ret->type = XPATH_STRING;
2011 ret->stringval = val;
2012#ifdef XP_DEBUG_OBJ_USAGE
2013 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2014#endif
2015 return(ret);
2016 } else if ((cache->miscObjs != NULL) &&
2017 (cache->miscObjs->number != 0))
2018 {
2019 xmlXPathObjectPtr ret;
2020 /*
2021 * Fallback to misc-cache.
2022 */
2023 ret = (xmlXPathObjectPtr)
2024 cache->miscObjs->items[--cache->miscObjs->number];
2025
2026 ret->type = XPATH_STRING;
2027 ret->stringval = val;
2028#ifdef XP_DEBUG_OBJ_USAGE
2029 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2030#endif
2031 return(ret);
2032 }
2033 }
2034 return(xmlXPathWrapString(val));
2035}
2036
2037/**
2038 * xmlXPathCacheNewNodeSet:
2039 * @ctxt: the XPath context
2040 * @val: the NodePtr value
2041 *
2042 * This is the cached version of xmlXPathNewNodeSet().
2043 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2044 * it with the single Node @val
2045 *
2046 * Returns the created or reused object.
2047 */
2048static xmlXPathObjectPtr
2049xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2050{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002051 if ((ctxt != NULL) && (ctxt->cache)) {
2052 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002053
2054 if ((cache->nodesetObjs != NULL) &&
2055 (cache->nodesetObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002056 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002057 xmlXPathObjectPtr ret;
2058 /*
2059 * Use the nodset-cache.
Daniel Veillard45490ae2008-07-29 09:13:19 +00002060 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002061 ret = (xmlXPathObjectPtr)
2062 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2063 ret->type = XPATH_NODESET;
2064 ret->boolval = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002065 if (val) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002066 if ((ret->nodesetval->nodeMax == 0) ||
2067 (val->type == XML_NAMESPACE_DECL))
2068 {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002069 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002070 } else {
2071 ret->nodesetval->nodeTab[0] = val;
2072 ret->nodesetval->nodeNr = 1;
2073 }
2074 }
2075#ifdef XP_DEBUG_OBJ_USAGE
2076 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2077#endif
2078 return(ret);
2079 } else if ((cache->miscObjs != NULL) &&
2080 (cache->miscObjs->number != 0))
2081 {
2082 xmlXPathObjectPtr ret;
2083 /*
2084 * Fallback to misc-cache.
2085 */
2086
2087 ret = (xmlXPathObjectPtr)
2088 cache->miscObjs->items[--cache->miscObjs->number];
2089
2090 ret->type = XPATH_NODESET;
2091 ret->boolval = 0;
2092 ret->nodesetval = xmlXPathNodeSetCreate(val);
2093#ifdef XP_DEBUG_OBJ_USAGE
2094 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2095#endif
2096 return(ret);
2097 }
2098 }
2099 return(xmlXPathNewNodeSet(val));
2100}
2101
2102/**
2103 * xmlXPathCacheNewCString:
2104 * @ctxt: the XPath context
2105 * @val: the char * value
2106 *
2107 * This is the cached version of xmlXPathNewCString().
2108 * Acquire an xmlXPathObjectPtr of type string and of value @val
2109 *
2110 * Returns the created or reused object.
2111 */
2112static xmlXPathObjectPtr
2113xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002114{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002115 if ((ctxt != NULL) && (ctxt->cache)) {
2116 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002117
2118 if ((cache->stringObjs != NULL) &&
2119 (cache->stringObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002120 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002121 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002122
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002123 ret = (xmlXPathObjectPtr)
2124 cache->stringObjs->items[--cache->stringObjs->number];
2125
2126 ret->type = XPATH_STRING;
2127 ret->stringval = xmlStrdup(BAD_CAST val);
2128#ifdef XP_DEBUG_OBJ_USAGE
2129 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2130#endif
2131 return(ret);
2132 } else if ((cache->miscObjs != NULL) &&
2133 (cache->miscObjs->number != 0))
2134 {
2135 xmlXPathObjectPtr ret;
2136
2137 ret = (xmlXPathObjectPtr)
2138 cache->miscObjs->items[--cache->miscObjs->number];
2139
2140 ret->type = XPATH_STRING;
2141 ret->stringval = xmlStrdup(BAD_CAST val);
2142#ifdef XP_DEBUG_OBJ_USAGE
2143 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2144#endif
2145 return(ret);
2146 }
2147 }
2148 return(xmlXPathNewCString(val));
2149}
2150
2151/**
2152 * xmlXPathCacheNewString:
2153 * @ctxt: the XPath context
2154 * @val: the xmlChar * value
2155 *
2156 * This is the cached version of xmlXPathNewString().
2157 * Acquire an xmlXPathObjectPtr of type string and of value @val
2158 *
2159 * Returns the created or reused object.
2160 */
2161static xmlXPathObjectPtr
2162xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002163{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002164 if ((ctxt != NULL) && (ctxt->cache)) {
2165 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002166
2167 if ((cache->stringObjs != NULL) &&
2168 (cache->stringObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002169 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002170 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002171
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002172 ret = (xmlXPathObjectPtr)
2173 cache->stringObjs->items[--cache->stringObjs->number];
2174 ret->type = XPATH_STRING;
2175 if (val != NULL)
2176 ret->stringval = xmlStrdup(val);
2177 else
2178 ret->stringval = xmlStrdup((const xmlChar *)"");
2179#ifdef XP_DEBUG_OBJ_USAGE
2180 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2181#endif
2182 return(ret);
2183 } else if ((cache->miscObjs != NULL) &&
2184 (cache->miscObjs->number != 0))
2185 {
2186 xmlXPathObjectPtr ret;
2187
2188 ret = (xmlXPathObjectPtr)
2189 cache->miscObjs->items[--cache->miscObjs->number];
2190
2191 ret->type = XPATH_STRING;
2192 if (val != NULL)
2193 ret->stringval = xmlStrdup(val);
2194 else
2195 ret->stringval = xmlStrdup((const xmlChar *)"");
2196#ifdef XP_DEBUG_OBJ_USAGE
2197 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2198#endif
2199 return(ret);
2200 }
2201 }
2202 return(xmlXPathNewString(val));
2203}
2204
2205/**
2206 * xmlXPathCacheNewBoolean:
2207 * @ctxt: the XPath context
2208 * @val: the boolean value
2209 *
2210 * This is the cached version of xmlXPathNewBoolean().
2211 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2212 *
2213 * Returns the created or reused object.
2214 */
2215static xmlXPathObjectPtr
2216xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002217{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002218 if ((ctxt != NULL) && (ctxt->cache)) {
2219 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002220
2221 if ((cache->booleanObjs != NULL) &&
2222 (cache->booleanObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002223 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002224 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002225
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002226 ret = (xmlXPathObjectPtr)
2227 cache->booleanObjs->items[--cache->booleanObjs->number];
2228 ret->type = XPATH_BOOLEAN;
2229 ret->boolval = (val != 0);
2230#ifdef XP_DEBUG_OBJ_USAGE
2231 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2232#endif
2233 return(ret);
2234 } else if ((cache->miscObjs != NULL) &&
2235 (cache->miscObjs->number != 0))
2236 {
2237 xmlXPathObjectPtr ret;
2238
2239 ret = (xmlXPathObjectPtr)
2240 cache->miscObjs->items[--cache->miscObjs->number];
2241
2242 ret->type = XPATH_BOOLEAN;
2243 ret->boolval = (val != 0);
2244#ifdef XP_DEBUG_OBJ_USAGE
2245 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2246#endif
2247 return(ret);
2248 }
2249 }
2250 return(xmlXPathNewBoolean(val));
2251}
2252
2253/**
2254 * xmlXPathCacheNewFloat:
2255 * @ctxt: the XPath context
2256 * @val: the double value
2257 *
2258 * This is the cached version of xmlXPathNewFloat().
2259 * Acquires an xmlXPathObjectPtr of type double and of value @val
2260 *
2261 * Returns the created or reused object.
2262 */
2263static xmlXPathObjectPtr
2264xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2265{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002266 if ((ctxt != NULL) && (ctxt->cache)) {
2267 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002268
2269 if ((cache->numberObjs != NULL) &&
2270 (cache->numberObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002271 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002272 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002273
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002274 ret = (xmlXPathObjectPtr)
2275 cache->numberObjs->items[--cache->numberObjs->number];
2276 ret->type = XPATH_NUMBER;
2277 ret->floatval = val;
2278#ifdef XP_DEBUG_OBJ_USAGE
2279 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2280#endif
2281 return(ret);
2282 } else if ((cache->miscObjs != NULL) &&
2283 (cache->miscObjs->number != 0))
2284 {
2285 xmlXPathObjectPtr ret;
2286
2287 ret = (xmlXPathObjectPtr)
2288 cache->miscObjs->items[--cache->miscObjs->number];
2289
2290 ret->type = XPATH_NUMBER;
2291 ret->floatval = val;
2292#ifdef XP_DEBUG_OBJ_USAGE
2293 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2294#endif
2295 return(ret);
2296 }
2297 }
2298 return(xmlXPathNewFloat(val));
2299}
2300
2301/**
2302 * xmlXPathCacheConvertString:
2303 * @ctxt: the XPath context
2304 * @val: an XPath object
2305 *
2306 * This is the cached version of xmlXPathConvertString().
2307 * Converts an existing object to its string() equivalent
2308 *
2309 * Returns a created or reused object, the old one is freed (cached)
2310 * (or the operation is done directly on @val)
2311 */
2312
2313static xmlXPathObjectPtr
2314xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002315 xmlChar *res = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002316
2317 if (val == NULL)
2318 return(xmlXPathCacheNewCString(ctxt, ""));
2319
2320 switch (val->type) {
2321 case XPATH_UNDEFINED:
2322#ifdef DEBUG_EXPR
2323 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2324#endif
2325 break;
2326 case XPATH_NODESET:
2327 case XPATH_XSLT_TREE:
2328 res = xmlXPathCastNodeSetToString(val->nodesetval);
2329 break;
2330 case XPATH_STRING:
2331 return(val);
2332 case XPATH_BOOLEAN:
2333 res = xmlXPathCastBooleanToString(val->boolval);
2334 break;
2335 case XPATH_NUMBER:
2336 res = xmlXPathCastNumberToString(val->floatval);
2337 break;
2338 case XPATH_USERS:
2339 case XPATH_POINT:
2340 case XPATH_RANGE:
2341 case XPATH_LOCATIONSET:
2342 TODO;
2343 break;
2344 }
2345 xmlXPathReleaseObject(ctxt, val);
2346 if (res == NULL)
2347 return(xmlXPathCacheNewCString(ctxt, ""));
2348 return(xmlXPathCacheWrapString(ctxt, res));
2349}
2350
2351/**
2352 * xmlXPathCacheObjectCopy:
2353 * @ctxt: the XPath context
2354 * @val: the original object
2355 *
2356 * This is the cached version of xmlXPathObjectCopy().
2357 * Acquire a copy of a given object
2358 *
2359 * Returns a created or reused created object.
2360 */
2361static xmlXPathObjectPtr
2362xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2363{
2364 if (val == NULL)
2365 return(NULL);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002366
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002367 if (XP_HAS_CACHE(ctxt)) {
2368 switch (val->type) {
2369 case XPATH_NODESET:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002370 return(xmlXPathCacheWrapNodeSet(ctxt,
2371 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002372 case XPATH_STRING:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002373 return(xmlXPathCacheNewString(ctxt, val->stringval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002374 case XPATH_BOOLEAN:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002375 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002376 case XPATH_NUMBER:
2377 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2378 default:
2379 break;
2380 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002381 }
2382 return(xmlXPathObjectCopy(val));
2383}
2384
2385/**
2386 * xmlXPathCacheConvertBoolean:
2387 * @ctxt: the XPath context
2388 * @val: an XPath object
2389 *
2390 * This is the cached version of xmlXPathConvertBoolean().
2391 * Converts an existing object to its boolean() equivalent
2392 *
2393 * Returns a created or reused object, the old one is freed (or the operation
2394 * is done directly on @val)
2395 */
2396static xmlXPathObjectPtr
2397xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2398 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002399
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002400 if (val == NULL)
2401 return(xmlXPathCacheNewBoolean(ctxt, 0));
2402 if (val->type == XPATH_BOOLEAN)
2403 return(val);
2404 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2405 xmlXPathReleaseObject(ctxt, val);
2406 return(ret);
2407}
2408
2409/**
2410 * xmlXPathCacheConvertNumber:
2411 * @ctxt: the XPath context
2412 * @val: an XPath object
2413 *
2414 * This is the cached version of xmlXPathConvertNumber().
2415 * Converts an existing object to its number() equivalent
2416 *
2417 * Returns a created or reused object, the old one is freed (or the operation
2418 * is done directly on @val)
2419 */
2420static xmlXPathObjectPtr
2421xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2422 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002423
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002424 if (val == NULL)
2425 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2426 if (val->type == XPATH_NUMBER)
2427 return(val);
2428 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2429 xmlXPathReleaseObject(ctxt, val);
2430 return(ret);
2431}
2432
2433/************************************************************************
2434 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +00002435 * Parser stacks related functions and macros *
Owen Taylor3473f882001-02-23 17:55:21 +00002436 * *
2437 ************************************************************************/
2438
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002439/**
Daniel Veillardf5048b32011-08-18 17:10:13 +08002440 * xmlXPathSetFrame:
2441 * @ctxt: an XPath parser context
2442 *
2443 * Set the callee evaluation frame
2444 *
2445 * Returns the previous frame value to be restored once done
2446 */
2447static int
2448xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2449 int ret;
2450
2451 if (ctxt == NULL)
2452 return(0);
2453 ret = ctxt->valueFrame;
2454 ctxt->valueFrame = ctxt->valueNr;
2455 return(ret);
2456}
2457
2458/**
2459 * xmlXPathPopFrame:
2460 * @ctxt: an XPath parser context
2461 * @frame: the previous frame value
2462 *
2463 * Remove the callee evaluation frame
2464 */
2465static void
2466xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2467 if (ctxt == NULL)
2468 return;
2469 if (ctxt->valueNr < ctxt->valueFrame) {
2470 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2471 }
2472 ctxt->valueFrame = frame;
2473}
2474
2475/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002476 * valuePop:
2477 * @ctxt: an XPath evaluation context
2478 *
2479 * Pops the top XPath object from the value stack
2480 *
2481 * Returns the XPath object just removed
2482 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002483xmlXPathObjectPtr
Daniel Veillard1c732d22002-11-30 11:22:59 +00002484valuePop(xmlXPathParserContextPtr ctxt)
2485{
2486 xmlXPathObjectPtr ret;
2487
Daniel Veillarda82b1822004-11-08 16:24:57 +00002488 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
Daniel Veillard24505b02005-07-28 23:49:35 +00002489 return (NULL);
Daniel Veillardf5048b32011-08-18 17:10:13 +08002490
2491 if (ctxt->valueNr <= ctxt->valueFrame) {
2492 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2493 return (NULL);
2494 }
2495
Daniel Veillard1c732d22002-11-30 11:22:59 +00002496 ctxt->valueNr--;
2497 if (ctxt->valueNr > 0)
2498 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2499 else
2500 ctxt->value = NULL;
2501 ret = ctxt->valueTab[ctxt->valueNr];
Daniel Veillard24505b02005-07-28 23:49:35 +00002502 ctxt->valueTab[ctxt->valueNr] = NULL;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002503 return (ret);
2504}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002505/**
2506 * valuePush:
2507 * @ctxt: an XPath evaluation context
2508 * @value: the XPath object
2509 *
2510 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002511 *
2512 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002513 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002514int
Daniel Veillard1c732d22002-11-30 11:22:59 +00002515valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2516{
Daniel Veillarda82b1822004-11-08 16:24:57 +00002517 if ((ctxt == NULL) || (value == NULL)) return(-1);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002518 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002519 xmlXPathObjectPtr *tmp;
2520
Daniel Veillardcd852ad2012-07-30 10:12:18 +08002521 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2522 xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
2523 ctxt->error = XPATH_MEMORY_ERROR;
2524 return (0);
2525 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002526 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2527 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00002528 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002529 if (tmp == NULL) {
Daniel Veillardcd852ad2012-07-30 10:12:18 +08002530 xmlXPathErrMemory(NULL, "pushing value\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08002531 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002532 return (0);
2533 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002534 ctxt->valueMax *= 2;
2535 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002536 }
2537 ctxt->valueTab[ctxt->valueNr] = value;
2538 ctxt->value = value;
2539 return (ctxt->valueNr++);
2540}
Owen Taylor3473f882001-02-23 17:55:21 +00002541
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002542/**
2543 * xmlXPathPopBoolean:
2544 * @ctxt: an XPath parser context
2545 *
2546 * Pops a boolean from the stack, handling conversion if needed.
2547 * Check error with #xmlXPathCheckError.
2548 *
2549 * Returns the boolean
2550 */
2551int
2552xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2553 xmlXPathObjectPtr obj;
2554 int ret;
2555
2556 obj = valuePop(ctxt);
2557 if (obj == NULL) {
2558 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2559 return(0);
2560 }
William M. Brack08171912003-12-29 02:52:11 +00002561 if (obj->type != XPATH_BOOLEAN)
2562 ret = xmlXPathCastToBoolean(obj);
2563 else
2564 ret = obj->boolval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002565 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002566 return(ret);
2567}
2568
2569/**
2570 * xmlXPathPopNumber:
2571 * @ctxt: an XPath parser context
2572 *
2573 * Pops a number from the stack, handling conversion if needed.
2574 * Check error with #xmlXPathCheckError.
2575 *
2576 * Returns the number
2577 */
2578double
2579xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2580 xmlXPathObjectPtr obj;
2581 double ret;
2582
2583 obj = valuePop(ctxt);
2584 if (obj == NULL) {
2585 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2586 return(0);
2587 }
William M. Brack08171912003-12-29 02:52:11 +00002588 if (obj->type != XPATH_NUMBER)
2589 ret = xmlXPathCastToNumber(obj);
2590 else
2591 ret = obj->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002592 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002593 return(ret);
2594}
2595
2596/**
2597 * xmlXPathPopString:
2598 * @ctxt: an XPath parser context
2599 *
2600 * Pops a string from the stack, handling conversion if needed.
2601 * Check error with #xmlXPathCheckError.
2602 *
2603 * Returns the string
2604 */
2605xmlChar *
2606xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2607 xmlXPathObjectPtr obj;
2608 xmlChar * ret;
2609
2610 obj = valuePop(ctxt);
2611 if (obj == NULL) {
2612 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2613 return(NULL);
2614 }
William M. Brack08171912003-12-29 02:52:11 +00002615 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002616 /* TODO: needs refactoring somewhere else */
2617 if (obj->stringval == ret)
2618 obj->stringval = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002619 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002620 return(ret);
2621}
2622
2623/**
2624 * xmlXPathPopNodeSet:
2625 * @ctxt: an XPath parser context
2626 *
2627 * Pops a node-set from the stack, handling conversion if needed.
2628 * Check error with #xmlXPathCheckError.
2629 *
2630 * Returns the node-set
2631 */
2632xmlNodeSetPtr
2633xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2634 xmlXPathObjectPtr obj;
2635 xmlNodeSetPtr ret;
2636
Daniel Veillardf2a36f92004-11-08 17:55:01 +00002637 if (ctxt == NULL) return(NULL);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002638 if (ctxt->value == NULL) {
2639 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2640 return(NULL);
2641 }
2642 if (!xmlXPathStackIsNodeSet(ctxt)) {
2643 xmlXPathSetTypeError(ctxt);
2644 return(NULL);
2645 }
2646 obj = valuePop(ctxt);
2647 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00002648#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00002649 /* to fix memory leak of not clearing obj->user */
2650 if (obj->boolval && obj->user != NULL)
2651 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00002652#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002653 obj->nodesetval = NULL;
2654 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002655 return(ret);
2656}
2657
2658/**
2659 * xmlXPathPopExternal:
2660 * @ctxt: an XPath parser context
2661 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002662 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002663 * Check error with #xmlXPathCheckError.
2664 *
2665 * Returns the object
2666 */
2667void *
2668xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2669 xmlXPathObjectPtr obj;
2670 void * ret;
2671
Daniel Veillarda82b1822004-11-08 16:24:57 +00002672 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002673 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2674 return(NULL);
2675 }
2676 if (ctxt->value->type != XPATH_USERS) {
2677 xmlXPathSetTypeError(ctxt);
2678 return(NULL);
2679 }
2680 obj = valuePop(ctxt);
2681 ret = obj->user;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002682 obj->user = NULL;
2683 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002684 return(ret);
2685}
2686
Owen Taylor3473f882001-02-23 17:55:21 +00002687/*
2688 * Macros for accessing the content. Those should be used only by the parser,
2689 * and not exported.
2690 *
2691 * Dirty macros, i.e. one need to make assumption on the context to use them
2692 *
2693 * CUR_PTR return the current pointer to the xmlChar to be parsed.
2694 * CUR returns the current xmlChar value, i.e. a 8 bit value
2695 * in ISO-Latin or UTF-8.
2696 * This should be used internally by the parser
2697 * only to compare to ASCII values otherwise it would break when
2698 * running with UTF-8 encoding.
2699 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
2700 * to compare on ASCII based substring.
2701 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2702 * strings within the parser.
2703 * CURRENT Returns the current char value, with the full decoding of
2704 * UTF-8 if we are using this mode. It returns an int.
2705 * NEXT Skip to the next character, this does the proper decoding
2706 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
2707 * It returns the pointer to the current xmlChar.
2708 */
2709
2710#define CUR (*ctxt->cur)
2711#define SKIP(val) ctxt->cur += (val)
2712#define NXT(val) ctxt->cur[(val)]
2713#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00002714#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2715
2716#define COPY_BUF(l,b,i,v) \
2717 if (l == 1) b[i++] = (xmlChar) v; \
2718 else i += xmlCopyChar(l,&b[i],v)
2719
2720#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00002721
Daniel Veillard45490ae2008-07-29 09:13:19 +00002722#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00002723 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00002724
2725#define CURRENT (*ctxt->cur)
2726#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
2727
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002728
2729#ifndef DBL_DIG
2730#define DBL_DIG 16
2731#endif
2732#ifndef DBL_EPSILON
2733#define DBL_EPSILON 1E-9
2734#endif
2735
2736#define UPPER_DOUBLE 1E9
2737#define LOWER_DOUBLE 1E-5
William M. Brackca797882007-05-11 14:45:53 +00002738#define LOWER_DOUBLE_EXP 5
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002739
2740#define INTEGER_DIGITS DBL_DIG
William M. Brackca797882007-05-11 14:45:53 +00002741#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002742#define EXPONENT_DIGITS (3 + 2)
2743
2744/**
2745 * xmlXPathFormatNumber:
2746 * @number: number to format
2747 * @buffer: output buffer
2748 * @buffersize: size of output buffer
2749 *
2750 * Convert the number into a string representation.
2751 */
2752static void
2753xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2754{
Daniel Veillardcda96922001-08-21 10:56:31 +00002755 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002756 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00002757 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002758 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002759 break;
2760 case -1:
2761 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002762 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002763 break;
2764 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00002765 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002766 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002767 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00002768 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002769 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002770 } else if (number == ((int) number)) {
2771 char work[30];
2772 char *ptr, *cur;
Daniel Veillardb3d14912005-09-04 20:47:39 +00002773 int value = (int) number;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002774
2775 ptr = &buffer[0];
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002776 if (value == 0) {
2777 *ptr++ = '0';
2778 } else {
Daniel Veillardb3d14912005-09-04 20:47:39 +00002779 snprintf(work, 29, "%d", value);
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002780 cur = &work[0];
Daniel Veillardb3d14912005-09-04 20:47:39 +00002781 while ((*cur) && (ptr - buffer < buffersize)) {
2782 *ptr++ = *cur++;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002783 }
2784 }
2785 if (ptr - buffer < buffersize) {
2786 *ptr = 0;
2787 } else if (buffersize > 0) {
2788 ptr--;
2789 *ptr = 0;
2790 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002791 } else {
William M. Brackca797882007-05-11 14:45:53 +00002792 /*
2793 For the dimension of work,
2794 DBL_DIG is number of significant digits
2795 EXPONENT is only needed for "scientific notation"
2796 3 is sign, decimal point, and terminating zero
2797 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2798 Note that this dimension is slightly (a few characters)
2799 larger than actually necessary.
2800 */
2801 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
Bjorn Reese70a9da52001-04-21 16:57:29 +00002802 int integer_place, fraction_place;
2803 char *ptr;
2804 char *after_fraction;
2805 double absolute_value;
2806 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002807
Bjorn Reese70a9da52001-04-21 16:57:29 +00002808 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002809
Bjorn Reese70a9da52001-04-21 16:57:29 +00002810 /*
2811 * First choose format - scientific or regular floating point.
2812 * In either case, result is in work, and after_fraction points
2813 * just past the fractional part.
2814 */
2815 if ( ((absolute_value > UPPER_DOUBLE) ||
2816 (absolute_value < LOWER_DOUBLE)) &&
2817 (absolute_value != 0.0) ) {
2818 /* Use scientific notation */
2819 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2820 fraction_place = DBL_DIG - 1;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002821 size = snprintf(work, sizeof(work),"%*.*e",
Bjorn Reese70a9da52001-04-21 16:57:29 +00002822 integer_place, fraction_place, number);
Daniel Veillard11ce4002006-03-10 00:36:23 +00002823 while ((size > 0) && (work[size] != 'e')) size--;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002824
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002825 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002826 else {
2827 /* Use regular notation */
William M. Brackca797882007-05-11 14:45:53 +00002828 if (absolute_value > 0.0) {
2829 integer_place = (int)log10(absolute_value);
2830 if (integer_place > 0)
2831 fraction_place = DBL_DIG - integer_place - 1;
2832 else
2833 fraction_place = DBL_DIG - integer_place;
2834 } else {
2835 fraction_place = 1;
2836 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002837 size = snprintf(work, sizeof(work), "%0.*f",
2838 fraction_place, number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002839 }
2840
Bjorn Reese70a9da52001-04-21 16:57:29 +00002841 /* Remove fractional trailing zeroes */
William M. Brackca797882007-05-11 14:45:53 +00002842 after_fraction = work + size;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002843 ptr = after_fraction;
2844 while (*(--ptr) == '0')
2845 ;
2846 if (*ptr != '.')
2847 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002848 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002849
2850 /* Finally copy result back to caller */
2851 size = strlen(work) + 1;
2852 if (size > buffersize) {
2853 work[buffersize - 1] = 0;
2854 size = buffersize;
2855 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002856 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002857 }
2858 break;
2859 }
2860}
2861
Owen Taylor3473f882001-02-23 17:55:21 +00002862
2863/************************************************************************
2864 * *
2865 * Routines to handle NodeSets *
2866 * *
2867 ************************************************************************/
2868
2869/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002870 * xmlXPathOrderDocElems:
2871 * @doc: an input document
2872 *
2873 * Call this routine to speed up XPath computation on static documents.
2874 * This stamps all the element nodes with the document order
2875 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00002876 * field, the value stored is actually - the node number (starting at -1)
2877 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002878 *
William M. Brack08171912003-12-29 02:52:11 +00002879 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002880 * of error.
2881 */
2882long
2883xmlXPathOrderDocElems(xmlDocPtr doc) {
2884 long count = 0;
2885 xmlNodePtr cur;
2886
2887 if (doc == NULL)
2888 return(-1);
2889 cur = doc->children;
2890 while (cur != NULL) {
2891 if (cur->type == XML_ELEMENT_NODE) {
2892 cur->content = (void *) (-(++count));
2893 if (cur->children != NULL) {
2894 cur = cur->children;
2895 continue;
2896 }
2897 }
2898 if (cur->next != NULL) {
2899 cur = cur->next;
2900 continue;
2901 }
2902 do {
2903 cur = cur->parent;
2904 if (cur == NULL)
2905 break;
2906 if (cur == (xmlNodePtr) doc) {
2907 cur = NULL;
2908 break;
2909 }
2910 if (cur->next != NULL) {
2911 cur = cur->next;
2912 break;
2913 }
2914 } while (cur != NULL);
2915 }
2916 return(count);
2917}
2918
2919/**
Owen Taylor3473f882001-02-23 17:55:21 +00002920 * xmlXPathCmpNodes:
2921 * @node1: the first node
2922 * @node2: the second node
2923 *
2924 * Compare two nodes w.r.t document order
2925 *
2926 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00002927 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00002928 */
2929int
2930xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2931 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002932 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002933 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002934 xmlNodePtr cur, root;
2935
2936 if ((node1 == NULL) || (node2 == NULL))
2937 return(-2);
2938 /*
2939 * a couple of optimizations which will avoid computations in most cases
2940 */
William M. Brackee0b9822007-03-07 08:15:01 +00002941 if (node1 == node2) /* trivial case */
2942 return(0);
Daniel Veillardedfd5882003-03-07 14:20:40 +00002943 if (node1->type == XML_ATTRIBUTE_NODE) {
2944 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002945 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002946 node1 = node1->parent;
2947 }
2948 if (node2->type == XML_ATTRIBUTE_NODE) {
2949 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002950 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002951 node2 = node2->parent;
2952 }
2953 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00002954 if (attr1 == attr2) {
2955 /* not required, but we keep attributes in order */
2956 if (attr1 != 0) {
2957 cur = attrNode2->prev;
2958 while (cur != NULL) {
2959 if (cur == attrNode1)
2960 return (1);
2961 cur = cur->prev;
2962 }
2963 return (-1);
2964 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00002965 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00002966 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00002967 if (attr2 == 1)
2968 return(1);
2969 return(-1);
2970 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002971 if ((node1->type == XML_NAMESPACE_DECL) ||
2972 (node2->type == XML_NAMESPACE_DECL))
2973 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00002974 if (node1 == node2->prev)
2975 return(1);
2976 if (node1 == node2->next)
2977 return(-1);
2978
2979 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002980 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002981 */
2982 if ((node1->type == XML_ELEMENT_NODE) &&
2983 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002984 (0 > (long) node1->content) &&
2985 (0 > (long) node2->content) &&
2986 (node1->doc == node2->doc)) {
2987 long l1, l2;
2988
2989 l1 = -((long) node1->content);
2990 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002991 if (l1 < l2)
2992 return(1);
2993 if (l1 > l2)
2994 return(-1);
2995 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002996
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002997 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002998 * compute depth to root
2999 */
3000 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3001 if (cur == node1)
3002 return(1);
3003 depth2++;
3004 }
3005 root = cur;
3006 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3007 if (cur == node2)
3008 return(-1);
3009 depth1++;
3010 }
3011 /*
3012 * Distinct document (or distinct entities :-( ) case.
3013 */
3014 if (root != cur) {
3015 return(-2);
3016 }
3017 /*
3018 * get the nearest common ancestor.
3019 */
3020 while (depth1 > depth2) {
3021 depth1--;
3022 node1 = node1->parent;
3023 }
3024 while (depth2 > depth1) {
3025 depth2--;
3026 node2 = node2->parent;
3027 }
3028 while (node1->parent != node2->parent) {
3029 node1 = node1->parent;
3030 node2 = node2->parent;
3031 /* should not happen but just in case ... */
3032 if ((node1 == NULL) || (node2 == NULL))
3033 return(-2);
3034 }
3035 /*
3036 * Find who's first.
3037 */
Daniel Veillardf49be472004-02-17 11:48:18 +00003038 if (node1 == node2->prev)
3039 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00003040 if (node1 == node2->next)
3041 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00003042 /*
3043 * Speedup using document order if availble.
3044 */
3045 if ((node1->type == XML_ELEMENT_NODE) &&
3046 (node2->type == XML_ELEMENT_NODE) &&
3047 (0 > (long) node1->content) &&
3048 (0 > (long) node2->content) &&
3049 (node1->doc == node2->doc)) {
3050 long l1, l2;
3051
3052 l1 = -((long) node1->content);
3053 l2 = -((long) node2->content);
3054 if (l1 < l2)
3055 return(1);
3056 if (l1 > l2)
3057 return(-1);
3058 }
3059
Owen Taylor3473f882001-02-23 17:55:21 +00003060 for (cur = node1->next;cur != NULL;cur = cur->next)
3061 if (cur == node2)
3062 return(1);
3063 return(-1); /* assume there is no sibling list corruption */
3064}
3065
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003066#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003067/**
3068 * xmlXPathCmpNodesExt:
3069 * @node1: the first node
3070 * @node2: the second node
3071 *
3072 * Compare two nodes w.r.t document order.
3073 * This one is optimized for handling of non-element nodes.
3074 *
3075 * Returns -2 in case of error 1 if first point < second point, 0 if
3076 * it's the same node, -1 otherwise
3077 */
3078static int
3079xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
3080 int depth1, depth2;
3081 int misc = 0, precedence1 = 0, precedence2 = 0;
3082 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
3083 xmlNodePtr cur, root;
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003084 long l1, l2;
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003085
3086 if ((node1 == NULL) || (node2 == NULL))
3087 return(-2);
3088
3089 if (node1 == node2)
3090 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00003091
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003092 /*
3093 * a couple of optimizations which will avoid computations in most cases
Daniel Veillard45490ae2008-07-29 09:13:19 +00003094 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003095 switch (node1->type) {
3096 case XML_ELEMENT_NODE:
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003097 if (node2->type == XML_ELEMENT_NODE) {
3098 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
3099 (0 > (long) node2->content) &&
3100 (node1->doc == node2->doc))
Daniel Veillard45490ae2008-07-29 09:13:19 +00003101 {
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003102 l1 = -((long) node1->content);
3103 l2 = -((long) node2->content);
3104 if (l1 < l2)
3105 return(1);
3106 if (l1 > l2)
3107 return(-1);
3108 } else
Daniel Veillard45490ae2008-07-29 09:13:19 +00003109 goto turtle_comparison;
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003110 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003111 break;
3112 case XML_ATTRIBUTE_NODE:
3113 precedence1 = 1; /* element is owner */
3114 miscNode1 = node1;
3115 node1 = node1->parent;
3116 misc = 1;
3117 break;
3118 case XML_TEXT_NODE:
3119 case XML_CDATA_SECTION_NODE:
3120 case XML_COMMENT_NODE:
3121 case XML_PI_NODE: {
3122 miscNode1 = node1;
3123 /*
3124 * Find nearest element node.
Daniel Veillard45490ae2008-07-29 09:13:19 +00003125 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003126 if (node1->prev != NULL) {
3127 do {
3128 node1 = node1->prev;
3129 if (node1->type == XML_ELEMENT_NODE) {
3130 precedence1 = 3; /* element in prev-sibl axis */
3131 break;
3132 }
3133 if (node1->prev == NULL) {
3134 precedence1 = 2; /* element is parent */
3135 /*
3136 * URGENT TODO: Are there any cases, where the
3137 * parent of such a node is not an element node?
3138 */
3139 node1 = node1->parent;
3140 break;
3141 }
3142 } while (1);
3143 } else {
3144 precedence1 = 2; /* element is parent */
3145 node1 = node1->parent;
3146 }
William M. Brack31700e62007-06-13 20:33:02 +00003147 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
3148 (0 <= (long) node1->content)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003149 /*
3150 * Fallback for whatever case.
3151 */
3152 node1 = miscNode1;
3153 precedence1 = 0;
3154 } else
3155 misc = 1;
3156 }
3157 break;
3158 case XML_NAMESPACE_DECL:
3159 /*
3160 * TODO: why do we return 1 for namespace nodes?
3161 */
3162 return(1);
3163 default:
3164 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00003165 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003166 switch (node2->type) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00003167 case XML_ELEMENT_NODE:
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003168 break;
3169 case XML_ATTRIBUTE_NODE:
3170 precedence2 = 1; /* element is owner */
3171 miscNode2 = node2;
3172 node2 = node2->parent;
3173 misc = 1;
3174 break;
3175 case XML_TEXT_NODE:
3176 case XML_CDATA_SECTION_NODE:
3177 case XML_COMMENT_NODE:
3178 case XML_PI_NODE: {
3179 miscNode2 = node2;
3180 if (node2->prev != NULL) {
3181 do {
3182 node2 = node2->prev;
3183 if (node2->type == XML_ELEMENT_NODE) {
3184 precedence2 = 3; /* element in prev-sibl axis */
3185 break;
3186 }
3187 if (node2->prev == NULL) {
3188 precedence2 = 2; /* element is parent */
3189 node2 = node2->parent;
3190 break;
3191 }
3192 } while (1);
3193 } else {
3194 precedence2 = 2; /* element is parent */
3195 node2 = node2->parent;
Daniel Veillard45490ae2008-07-29 09:13:19 +00003196 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003197 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3198 (0 <= (long) node1->content))
3199 {
3200 node2 = miscNode2;
3201 precedence2 = 0;
3202 } else
3203 misc = 1;
3204 }
3205 break;
3206 case XML_NAMESPACE_DECL:
3207 return(1);
3208 default:
3209 break;
3210 }
3211 if (misc) {
3212 if (node1 == node2) {
3213 if (precedence1 == precedence2) {
3214 /*
3215 * The ugly case; but normally there aren't many
3216 * adjacent non-element nodes around.
3217 */
3218 cur = miscNode2->prev;
3219 while (cur != NULL) {
3220 if (cur == miscNode1)
3221 return(1);
3222 if (cur->type == XML_ELEMENT_NODE)
3223 return(-1);
3224 cur = cur->prev;
3225 }
3226 return (-1);
3227 } else {
3228 /*
3229 * Evaluate based on higher precedence wrt to the element.
3230 * TODO: This assumes attributes are sorted before content.
3231 * Is this 100% correct?
3232 */
3233 if (precedence1 < precedence2)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003234 return(1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003235 else
Daniel Veillard45490ae2008-07-29 09:13:19 +00003236 return(-1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003237 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00003238 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003239 /*
3240 * Special case: One of the helper-elements is contained by the other.
3241 * <foo>
3242 * <node2>
3243 * <node1>Text-1(precedence1 == 2)</node1>
3244 * </node2>
3245 * Text-6(precedence2 == 3)
3246 * </foo>
Daniel Veillard45490ae2008-07-29 09:13:19 +00003247 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003248 if ((precedence2 == 3) && (precedence1 > 1)) {
3249 cur = node1->parent;
3250 while (cur) {
3251 if (cur == node2)
3252 return(1);
3253 cur = cur->parent;
3254 }
3255 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00003256 if ((precedence1 == 3) && (precedence2 > 1)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003257 cur = node2->parent;
3258 while (cur) {
3259 if (cur == node1)
3260 return(-1);
3261 cur = cur->parent;
3262 }
3263 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00003264 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003265
3266 /*
3267 * Speedup using document order if availble.
3268 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00003269 if ((node1->type == XML_ELEMENT_NODE) &&
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003270 (node2->type == XML_ELEMENT_NODE) &&
3271 (0 > (long) node1->content) &&
3272 (0 > (long) node2->content) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +00003273 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003274
3275 l1 = -((long) node1->content);
3276 l2 = -((long) node2->content);
3277 if (l1 < l2)
3278 return(1);
3279 if (l1 > l2)
3280 return(-1);
3281 }
3282
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003283turtle_comparison:
3284
3285 if (node1 == node2->prev)
3286 return(1);
3287 if (node1 == node2->next)
3288 return(-1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003289 /*
3290 * compute depth to root
3291 */
3292 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3293 if (cur == node1)
3294 return(1);
3295 depth2++;
3296 }
3297 root = cur;
3298 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3299 if (cur == node2)
3300 return(-1);
3301 depth1++;
3302 }
3303 /*
3304 * Distinct document (or distinct entities :-( ) case.
3305 */
3306 if (root != cur) {
3307 return(-2);
3308 }
3309 /*
3310 * get the nearest common ancestor.
3311 */
3312 while (depth1 > depth2) {
3313 depth1--;
3314 node1 = node1->parent;
3315 }
3316 while (depth2 > depth1) {
3317 depth2--;
3318 node2 = node2->parent;
3319 }
3320 while (node1->parent != node2->parent) {
3321 node1 = node1->parent;
3322 node2 = node2->parent;
3323 /* should not happen but just in case ... */
3324 if ((node1 == NULL) || (node2 == NULL))
3325 return(-2);
3326 }
3327 /*
3328 * Find who's first.
3329 */
3330 if (node1 == node2->prev)
3331 return(1);
3332 if (node1 == node2->next)
3333 return(-1);
3334 /*
3335 * Speedup using document order if availble.
3336 */
3337 if ((node1->type == XML_ELEMENT_NODE) &&
3338 (node2->type == XML_ELEMENT_NODE) &&
3339 (0 > (long) node1->content) &&
3340 (0 > (long) node2->content) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +00003341 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003342
3343 l1 = -((long) node1->content);
3344 l2 = -((long) node2->content);
3345 if (l1 < l2)
3346 return(1);
3347 if (l1 > l2)
3348 return(-1);
3349 }
3350
3351 for (cur = node1->next;cur != NULL;cur = cur->next)
3352 if (cur == node2)
3353 return(1);
3354 return(-1); /* assume there is no sibling list corruption */
3355}
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003356#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003357
Owen Taylor3473f882001-02-23 17:55:21 +00003358/**
3359 * xmlXPathNodeSetSort:
3360 * @set: the node set
3361 *
3362 * Sort the node set in document order
3363 */
3364void
3365xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003366 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003367 xmlNodePtr tmp;
3368
3369 if (set == NULL)
3370 return;
3371
3372 /* Use Shell's sort to sort the node-set */
3373 len = set->nodeNr;
3374 for (incr = len / 2; incr > 0; incr /= 2) {
3375 for (i = incr; i < len; i++) {
3376 j = i - incr;
3377 while (j >= 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003378#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003379 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3380 set->nodeTab[j + incr]) == -1)
3381#else
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003382 if (xmlXPathCmpNodes(set->nodeTab[j],
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003383 set->nodeTab[j + incr]) == -1)
3384#endif
3385 {
Owen Taylor3473f882001-02-23 17:55:21 +00003386 tmp = set->nodeTab[j];
3387 set->nodeTab[j] = set->nodeTab[j + incr];
3388 set->nodeTab[j + incr] = tmp;
3389 j -= incr;
3390 } else
3391 break;
3392 }
3393 }
3394 }
3395}
3396
3397#define XML_NODESET_DEFAULT 10
3398/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003399 * xmlXPathNodeSetDupNs:
3400 * @node: the parent node of the namespace XPath node
3401 * @ns: the libxml namespace declaration node.
3402 *
3403 * Namespace node in libxml don't match the XPath semantic. In a node set
3404 * the namespace nodes are duplicated and the next pointer is set to the
3405 * parent node in the XPath semantic.
3406 *
3407 * Returns the newly created object.
3408 */
3409static xmlNodePtr
3410xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3411 xmlNsPtr cur;
3412
3413 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3414 return(NULL);
3415 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3416 return((xmlNodePtr) ns);
3417
3418 /*
3419 * Allocate a new Namespace and fill the fields.
3420 */
3421 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3422 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003423 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003424 return(NULL);
3425 }
3426 memset(cur, 0, sizeof(xmlNs));
3427 cur->type = XML_NAMESPACE_DECL;
3428 if (ns->href != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003429 cur->href = xmlStrdup(ns->href);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003430 if (ns->prefix != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003431 cur->prefix = xmlStrdup(ns->prefix);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003432 cur->next = (xmlNsPtr) node;
3433 return((xmlNodePtr) cur);
3434}
3435
3436/**
3437 * xmlXPathNodeSetFreeNs:
3438 * @ns: the XPath namespace node found in a nodeset.
3439 *
William M. Brack08171912003-12-29 02:52:11 +00003440 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003441 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00003442 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003443 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00003444void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003445xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3446 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3447 return;
3448
3449 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3450 if (ns->href != NULL)
3451 xmlFree((xmlChar *)ns->href);
3452 if (ns->prefix != NULL)
3453 xmlFree((xmlChar *)ns->prefix);
3454 xmlFree(ns);
3455 }
3456}
3457
3458/**
Owen Taylor3473f882001-02-23 17:55:21 +00003459 * xmlXPathNodeSetCreate:
3460 * @val: an initial xmlNodePtr, or NULL
3461 *
3462 * Create a new xmlNodeSetPtr of type double and of value @val
3463 *
3464 * Returns the newly created object.
3465 */
3466xmlNodeSetPtr
3467xmlXPathNodeSetCreate(xmlNodePtr val) {
3468 xmlNodeSetPtr ret;
3469
3470 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3471 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003472 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003473 return(NULL);
3474 }
3475 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3476 if (val != NULL) {
3477 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3478 sizeof(xmlNodePtr));
3479 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003480 xmlXPathErrMemory(NULL, "creating nodeset\n");
3481 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003482 return(NULL);
3483 }
3484 memset(ret->nodeTab, 0 ,
3485 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3486 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003487 if (val->type == XML_NAMESPACE_DECL) {
3488 xmlNsPtr ns = (xmlNsPtr) val;
3489
3490 ret->nodeTab[ret->nodeNr++] =
3491 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3492 } else
3493 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003494 }
3495 return(ret);
3496}
3497
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003498/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003499 * xmlXPathNodeSetCreateSize:
3500 * @size: the initial size of the set
3501 *
3502 * Create a new xmlNodeSetPtr of type double and of value @val
3503 *
3504 * Returns the newly created object.
3505 */
3506static xmlNodeSetPtr
3507xmlXPathNodeSetCreateSize(int size) {
3508 xmlNodeSetPtr ret;
3509
3510 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3511 if (ret == NULL) {
3512 xmlXPathErrMemory(NULL, "creating nodeset\n");
3513 return(NULL);
3514 }
3515 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3516 if (size < XML_NODESET_DEFAULT)
3517 size = XML_NODESET_DEFAULT;
3518 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3519 if (ret->nodeTab == NULL) {
3520 xmlXPathErrMemory(NULL, "creating nodeset\n");
3521 xmlFree(ret);
3522 return(NULL);
3523 }
3524 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
Daniel Veillard45490ae2008-07-29 09:13:19 +00003525 ret->nodeMax = size;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003526 return(ret);
3527}
3528
3529/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003530 * xmlXPathNodeSetContains:
3531 * @cur: the node-set
3532 * @val: the node
3533 *
3534 * checks whether @cur contains @val
3535 *
3536 * Returns true (1) if @cur contains @val, false (0) otherwise
3537 */
3538int
3539xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3540 int i;
3541
Daniel Veillarda82b1822004-11-08 16:24:57 +00003542 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003543 if (val->type == XML_NAMESPACE_DECL) {
3544 for (i = 0; i < cur->nodeNr; i++) {
3545 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3546 xmlNsPtr ns1, ns2;
3547
3548 ns1 = (xmlNsPtr) val;
3549 ns2 = (xmlNsPtr) cur->nodeTab[i];
3550 if (ns1 == ns2)
3551 return(1);
3552 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3553 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3554 return(1);
3555 }
3556 }
3557 } else {
3558 for (i = 0; i < cur->nodeNr; i++) {
3559 if (cur->nodeTab[i] == val)
3560 return(1);
3561 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003562 }
3563 return(0);
3564}
3565
3566/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003567 * xmlXPathNodeSetAddNs:
3568 * @cur: the initial node set
3569 * @node: the hosting node
3570 * @ns: a the namespace node
3571 *
3572 * add a new namespace node to an existing NodeSet
3573 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00003574void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003575xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3576 int i;
3577
Daniel Veillard45490ae2008-07-29 09:13:19 +00003578
Daniel Veillarda82b1822004-11-08 16:24:57 +00003579 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3580 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003581 (node->type != XML_ELEMENT_NODE))
3582 return;
3583
William M. Brack08171912003-12-29 02:52:11 +00003584 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003585 /*
William M. Brack08171912003-12-29 02:52:11 +00003586 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003587 */
3588 for (i = 0;i < cur->nodeNr;i++) {
3589 if ((cur->nodeTab[i] != NULL) &&
3590 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00003591 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003592 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3593 return;
3594 }
3595
3596 /*
3597 * grow the nodeTab if needed
3598 */
3599 if (cur->nodeMax == 0) {
3600 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3601 sizeof(xmlNodePtr));
3602 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003603 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003604 return;
3605 }
3606 memset(cur->nodeTab, 0 ,
3607 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3608 cur->nodeMax = XML_NODESET_DEFAULT;
3609 } else if (cur->nodeNr == cur->nodeMax) {
3610 xmlNodePtr *temp;
3611
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003612 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3613 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3614 return;
3615 }
Chris Evansd7958b22011-03-23 08:13:06 +08003616 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003617 sizeof(xmlNodePtr));
3618 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003619 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003620 return;
3621 }
Chris Evansd7958b22011-03-23 08:13:06 +08003622 cur->nodeMax *= 2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003623 cur->nodeTab = temp;
3624 }
3625 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3626}
3627
3628/**
Owen Taylor3473f882001-02-23 17:55:21 +00003629 * xmlXPathNodeSetAdd:
3630 * @cur: the initial node set
3631 * @val: a new xmlNodePtr
3632 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003633 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00003634 */
3635void
3636xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3637 int i;
3638
Daniel Veillarda82b1822004-11-08 16:24:57 +00003639 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003640
William M. Brack08171912003-12-29 02:52:11 +00003641 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003642 /*
William M. Brack08171912003-12-29 02:52:11 +00003643 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00003644 */
3645 for (i = 0;i < cur->nodeNr;i++)
3646 if (cur->nodeTab[i] == val) return;
3647
3648 /*
3649 * grow the nodeTab if needed
3650 */
3651 if (cur->nodeMax == 0) {
3652 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3653 sizeof(xmlNodePtr));
3654 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003655 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003656 return;
3657 }
3658 memset(cur->nodeTab, 0 ,
3659 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3660 cur->nodeMax = XML_NODESET_DEFAULT;
3661 } else if (cur->nodeNr == cur->nodeMax) {
3662 xmlNodePtr *temp;
3663
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003664 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3665 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3666 return;
3667 }
Daniel Veillard0cbeb502010-11-15 12:06:29 +01003668 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003669 sizeof(xmlNodePtr));
3670 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003671 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003672 return;
3673 }
Daniel Veillard0cbeb502010-11-15 12:06:29 +01003674 cur->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003675 cur->nodeTab = temp;
3676 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003677 if (val->type == XML_NAMESPACE_DECL) {
3678 xmlNsPtr ns = (xmlNsPtr) val;
3679
Daniel Veillard45490ae2008-07-29 09:13:19 +00003680 cur->nodeTab[cur->nodeNr++] =
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003681 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3682 } else
3683 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003684}
3685
3686/**
3687 * xmlXPathNodeSetAddUnique:
3688 * @cur: the initial node set
3689 * @val: a new xmlNodePtr
3690 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003691 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00003692 * when we are sure the node is not already in the set.
3693 */
3694void
3695xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00003696 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003697
William M. Brack08171912003-12-29 02:52:11 +00003698 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003699 /*
3700 * grow the nodeTab if needed
3701 */
3702 if (cur->nodeMax == 0) {
3703 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3704 sizeof(xmlNodePtr));
3705 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003706 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003707 return;
3708 }
3709 memset(cur->nodeTab, 0 ,
3710 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3711 cur->nodeMax = XML_NODESET_DEFAULT;
3712 } else if (cur->nodeNr == cur->nodeMax) {
3713 xmlNodePtr *temp;
3714
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003715 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3716 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3717 return;
3718 }
Chris Evansd7958b22011-03-23 08:13:06 +08003719 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003720 sizeof(xmlNodePtr));
3721 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003722 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003723 return;
3724 }
3725 cur->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08003726 cur->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003727 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003728 if (val->type == XML_NAMESPACE_DECL) {
3729 xmlNsPtr ns = (xmlNsPtr) val;
3730
Daniel Veillard45490ae2008-07-29 09:13:19 +00003731 cur->nodeTab[cur->nodeNr++] =
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003732 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3733 } else
3734 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003735}
3736
3737/**
3738 * xmlXPathNodeSetMerge:
3739 * @val1: the first NodeSet or NULL
3740 * @val2: the second NodeSet
3741 *
3742 * Merges two nodesets, all nodes from @val2 are added to @val1
3743 * if @val1 is NULL, a new set is created and copied from @val2
3744 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003745 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003746 */
3747xmlNodeSetPtr
3748xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003749 int i, j, initNr, skip;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003750 xmlNodePtr n1, n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003751
3752 if (val2 == NULL) return(val1);
3753 if (val1 == NULL) {
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003754 val1 = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00003755 if (val1 == NULL)
3756 return (NULL);
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003757#if 0
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003758 /*
3759 * TODO: The optimization won't work in every case, since
3760 * those nasty namespace nodes need to be added with
3761 * xmlXPathNodeSetDupNs() to the set; thus a pure
3762 * memcpy is not possible.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00003763 * If there was a flag on the nodesetval, indicating that
3764 * some temporary nodes are in, that would be helpfull.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003765 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00003766 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003767 * Optimization: Create an equally sized node-set
3768 * and memcpy the content.
3769 */
3770 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3771 if (val1 == NULL)
3772 return(NULL);
3773 if (val2->nodeNr != 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003774 if (val2->nodeNr == 1)
3775 *(val1->nodeTab) = *(val2->nodeTab);
3776 else {
3777 memcpy(val1->nodeTab, val2->nodeTab,
3778 val2->nodeNr * sizeof(xmlNodePtr));
3779 }
3780 val1->nodeNr = val2->nodeNr;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003781 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003782 return(val1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003783#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003784 }
3785
William M. Brack08171912003-12-29 02:52:11 +00003786 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003787 initNr = val1->nodeNr;
3788
3789 for (i = 0;i < val2->nodeNr;i++) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00003790 n2 = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00003791 /*
William M. Brack08171912003-12-29 02:52:11 +00003792 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003793 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003794 skip = 0;
3795 for (j = 0; j < initNr; j++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003796 n1 = val1->nodeTab[j];
3797 if (n1 == n2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003798 skip = 1;
3799 break;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003800 } else if ((n1->type == XML_NAMESPACE_DECL) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +00003801 (n2->type == XML_NAMESPACE_DECL)) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003802 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3803 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3804 ((xmlNsPtr) n2)->prefix)))
3805 {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003806 skip = 1;
3807 break;
3808 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003809 }
3810 }
3811 if (skip)
3812 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00003813
3814 /*
3815 * grow the nodeTab if needed
3816 */
3817 if (val1->nodeMax == 0) {
3818 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3819 sizeof(xmlNodePtr));
3820 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003821 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003822 return(NULL);
3823 }
3824 memset(val1->nodeTab, 0 ,
3825 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3826 val1->nodeMax = XML_NODESET_DEFAULT;
3827 } else if (val1->nodeNr == val1->nodeMax) {
3828 xmlNodePtr *temp;
3829
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003830 if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3831 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3832 return(NULL);
3833 }
Chris Evansd7958b22011-03-23 08:13:06 +08003834 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003835 sizeof(xmlNodePtr));
3836 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003837 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003838 return(NULL);
3839 }
3840 val1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08003841 val1->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003842 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003843 if (n2->type == XML_NAMESPACE_DECL) {
3844 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003845
3846 val1->nodeTab[val1->nodeNr++] =
3847 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3848 } else
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003849 val1->nodeTab[val1->nodeNr++] = n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003850 }
3851
3852 return(val1);
3853}
3854
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003855
3856/**
3857 * xmlXPathNodeSetMergeAndClear:
3858 * @set1: the first NodeSet or NULL
3859 * @set2: the second NodeSet
3860 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3861 *
3862 * Merges two nodesets, all nodes from @set2 are added to @set1
3863 * if @set1 is NULL, a new set is created and copied from @set2.
3864 * Checks for duplicate nodes. Clears set2.
3865 *
3866 * Returns @set1 once extended or NULL in case of error.
3867 */
3868static xmlNodeSetPtr
3869xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3870 int hasNullEntries)
3871{
3872 if ((set1 == NULL) && (hasNullEntries == 0)) {
3873 /*
3874 * Note that doing a memcpy of the list, namespace nodes are
3875 * just assigned to set1, since set2 is cleared anyway.
3876 */
3877 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3878 if (set1 == NULL)
3879 return(NULL);
3880 if (set2->nodeNr != 0) {
3881 memcpy(set1->nodeTab, set2->nodeTab,
3882 set2->nodeNr * sizeof(xmlNodePtr));
3883 set1->nodeNr = set2->nodeNr;
3884 }
3885 } else {
3886 int i, j, initNbSet1;
3887 xmlNodePtr n1, n2;
3888
3889 if (set1 == NULL)
Daniel Veillardf88d8492008-04-01 08:00:31 +00003890 set1 = xmlXPathNodeSetCreate(NULL);
3891 if (set1 == NULL)
3892 return (NULL);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003893
Daniel Veillard45490ae2008-07-29 09:13:19 +00003894 initNbSet1 = set1->nodeNr;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003895 for (i = 0;i < set2->nodeNr;i++) {
3896 n2 = set2->nodeTab[i];
3897 /*
3898 * Skip NULLed entries.
3899 */
3900 if (n2 == NULL)
3901 continue;
3902 /*
3903 * Skip duplicates.
3904 */
3905 for (j = 0; j < initNbSet1; j++) {
3906 n1 = set1->nodeTab[j];
Daniel Veillard45490ae2008-07-29 09:13:19 +00003907 if (n1 == n2) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003908 goto skip_node;
3909 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3910 (n2->type == XML_NAMESPACE_DECL))
Daniel Veillard45490ae2008-07-29 09:13:19 +00003911 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003912 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3913 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3914 ((xmlNsPtr) n2)->prefix)))
3915 {
3916 /*
3917 * Free the namespace node.
3918 */
3919 set2->nodeTab[i] = NULL;
3920 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3921 goto skip_node;
3922 }
3923 }
3924 }
3925 /*
3926 * grow the nodeTab if needed
3927 */
3928 if (set1->nodeMax == 0) {
3929 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3930 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3931 if (set1->nodeTab == NULL) {
3932 xmlXPathErrMemory(NULL, "merging nodeset\n");
3933 return(NULL);
3934 }
3935 memset(set1->nodeTab, 0,
3936 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3937 set1->nodeMax = XML_NODESET_DEFAULT;
3938 } else if (set1->nodeNr >= set1->nodeMax) {
3939 xmlNodePtr *temp;
Daniel Veillard45490ae2008-07-29 09:13:19 +00003940
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003941 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3942 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3943 return(NULL);
3944 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003945 temp = (xmlNodePtr *) xmlRealloc(
Chris Evansd7958b22011-03-23 08:13:06 +08003946 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003947 if (temp == NULL) {
3948 xmlXPathErrMemory(NULL, "merging nodeset\n");
3949 return(NULL);
3950 }
3951 set1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08003952 set1->nodeMax *= 2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003953 }
3954 if (n2->type == XML_NAMESPACE_DECL) {
3955 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard45490ae2008-07-29 09:13:19 +00003956
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003957 set1->nodeTab[set1->nodeNr++] =
3958 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3959 } else
3960 set1->nodeTab[set1->nodeNr++] = n2;
3961skip_node:
3962 {}
3963 }
3964 }
3965 set2->nodeNr = 0;
3966 return(set1);
3967}
3968
3969/**
3970 * xmlXPathNodeSetMergeAndClearNoDupls:
3971 * @set1: the first NodeSet or NULL
3972 * @set2: the second NodeSet
3973 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3974 *
3975 * Merges two nodesets, all nodes from @set2 are added to @set1
3976 * if @set1 is NULL, a new set is created and copied from @set2.
3977 * Doesn't chack for duplicate nodes. Clears set2.
3978 *
3979 * Returns @set1 once extended or NULL in case of error.
3980 */
3981static xmlNodeSetPtr
3982xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3983 int hasNullEntries)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003984{
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003985 if (set2 == NULL)
3986 return(set1);
3987 if ((set1 == NULL) && (hasNullEntries == 0)) {
3988 /*
3989 * Note that doing a memcpy of the list, namespace nodes are
3990 * just assigned to set1, since set2 is cleared anyway.
3991 */
3992 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3993 if (set1 == NULL)
3994 return(NULL);
3995 if (set2->nodeNr != 0) {
3996 memcpy(set1->nodeTab, set2->nodeTab,
3997 set2->nodeNr * sizeof(xmlNodePtr));
3998 set1->nodeNr = set2->nodeNr;
3999 }
4000 } else {
4001 int i;
4002 xmlNodePtr n2;
4003
4004 if (set1 == NULL)
4005 set1 = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004006 if (set1 == NULL)
4007 return (NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004008
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004009 for (i = 0;i < set2->nodeNr;i++) {
4010 n2 = set2->nodeTab[i];
4011 /*
4012 * Skip NULLed entries.
4013 */
4014 if (n2 == NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004015 continue;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004016 if (set1->nodeMax == 0) {
4017 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4018 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4019 if (set1->nodeTab == NULL) {
4020 xmlXPathErrMemory(NULL, "merging nodeset\n");
4021 return(NULL);
4022 }
4023 memset(set1->nodeTab, 0,
4024 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4025 set1->nodeMax = XML_NODESET_DEFAULT;
4026 } else if (set1->nodeNr >= set1->nodeMax) {
4027 xmlNodePtr *temp;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004028
Daniel Veillardcd852ad2012-07-30 10:12:18 +08004029 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4030 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4031 return(NULL);
4032 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004033 temp = (xmlNodePtr *) xmlRealloc(
Chris Evansd7958b22011-03-23 08:13:06 +08004034 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004035 if (temp == NULL) {
4036 xmlXPathErrMemory(NULL, "merging nodeset\n");
4037 return(NULL);
4038 }
4039 set1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08004040 set1->nodeMax *= 2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004041 }
4042 set1->nodeTab[set1->nodeNr++] = n2;
4043 }
4044 }
4045 set2->nodeNr = 0;
4046 return(set1);
4047}
Daniel Veillard75be0132002-03-13 10:03:35 +00004048
4049/**
Owen Taylor3473f882001-02-23 17:55:21 +00004050 * xmlXPathNodeSetDel:
4051 * @cur: the initial node set
4052 * @val: an xmlNodePtr
4053 *
4054 * Removes an xmlNodePtr from an existing NodeSet
4055 */
4056void
4057xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4058 int i;
4059
4060 if (cur == NULL) return;
4061 if (val == NULL) return;
4062
4063 /*
William M. Brack08171912003-12-29 02:52:11 +00004064 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00004065 */
4066 for (i = 0;i < cur->nodeNr;i++)
4067 if (cur->nodeTab[i] == val) break;
4068
William M. Brack08171912003-12-29 02:52:11 +00004069 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00004070#ifdef DEBUG
Daniel Veillard45490ae2008-07-29 09:13:19 +00004071 xmlGenericError(xmlGenericErrorContext,
Owen Taylor3473f882001-02-23 17:55:21 +00004072 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4073 val->name);
4074#endif
4075 return;
4076 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004077 if ((cur->nodeTab[i] != NULL) &&
4078 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4079 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004080 cur->nodeNr--;
4081 for (;i < cur->nodeNr;i++)
4082 cur->nodeTab[i] = cur->nodeTab[i + 1];
4083 cur->nodeTab[cur->nodeNr] = NULL;
4084}
4085
4086/**
4087 * xmlXPathNodeSetRemove:
4088 * @cur: the initial node set
4089 * @val: the index to remove
4090 *
4091 * Removes an entry from an existing NodeSet list.
4092 */
4093void
4094xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4095 if (cur == NULL) return;
4096 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004097 if ((cur->nodeTab[val] != NULL) &&
4098 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4099 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00004100 cur->nodeNr--;
4101 for (;val < cur->nodeNr;val++)
4102 cur->nodeTab[val] = cur->nodeTab[val + 1];
4103 cur->nodeTab[cur->nodeNr] = NULL;
4104}
4105
4106/**
4107 * xmlXPathFreeNodeSet:
4108 * @obj: the xmlNodeSetPtr to free
4109 *
4110 * Free the NodeSet compound (not the actual nodes !).
4111 */
4112void
4113xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4114 if (obj == NULL) return;
4115 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004116 int i;
4117
William M. Brack08171912003-12-29 02:52:11 +00004118 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004119 for (i = 0;i < obj->nodeNr;i++)
4120 if ((obj->nodeTab[i] != NULL) &&
4121 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4122 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004123 xmlFree(obj->nodeTab);
4124 }
Owen Taylor3473f882001-02-23 17:55:21 +00004125 xmlFree(obj);
4126}
4127
4128/**
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004129 * xmlXPathNodeSetClear:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004130 * @set: the node set to clear
Daniel Veillard45490ae2008-07-29 09:13:19 +00004131 *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004132 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4133 * are feed), but does *not* free the list itself. Sets the length of the
4134 * list to 0.
4135 */
4136static void
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004137xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4138{
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004139 if ((set == NULL) || (set->nodeNr <= 0))
4140 return;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004141 else if (hasNsNodes) {
4142 int i;
4143 xmlNodePtr node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004144
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004145 for (i = 0; i < set->nodeNr; i++) {
4146 node = set->nodeTab[i];
4147 if ((node != NULL) &&
4148 (node->type == XML_NAMESPACE_DECL))
4149 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004150 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004151 }
4152 set->nodeNr = 0;
4153}
4154
4155/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004156 * xmlXPathNodeSetClearFromPos:
4157 * @set: the node set to be cleared
4158 * @pos: the start position to clear from
Daniel Veillard45490ae2008-07-29 09:13:19 +00004159 *
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004160 * Clears the list from temporary XPath objects (e.g. namespace nodes
4161 * are feed) starting with the entry at @pos, but does *not* free the list
4162 * itself. Sets the length of the list to @pos.
4163 */
4164static void
4165xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4166{
4167 if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4168 return;
4169 else if ((hasNsNodes)) {
4170 int i;
4171 xmlNodePtr node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004172
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004173 for (i = pos; i < set->nodeNr; i++) {
4174 node = set->nodeTab[i];
4175 if ((node != NULL) &&
4176 (node->type == XML_NAMESPACE_DECL))
4177 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004178 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004179 }
4180 set->nodeNr = pos;
4181}
4182
4183/**
Owen Taylor3473f882001-02-23 17:55:21 +00004184 * xmlXPathFreeValueTree:
4185 * @obj: the xmlNodeSetPtr to free
4186 *
4187 * Free the NodeSet compound and the actual tree, this is different
4188 * from xmlXPathFreeNodeSet()
4189 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004190static void
Owen Taylor3473f882001-02-23 17:55:21 +00004191xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4192 int i;
4193
4194 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00004195
4196 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004197 for (i = 0;i < obj->nodeNr;i++) {
4198 if (obj->nodeTab[i] != NULL) {
4199 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4200 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4201 } else {
4202 xmlFreeNodeList(obj->nodeTab[i]);
4203 }
4204 }
4205 }
Owen Taylor3473f882001-02-23 17:55:21 +00004206 xmlFree(obj->nodeTab);
4207 }
Owen Taylor3473f882001-02-23 17:55:21 +00004208 xmlFree(obj);
4209}
4210
4211#if defined(DEBUG) || defined(DEBUG_STEP)
4212/**
4213 * xmlGenericErrorContextNodeSet:
4214 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00004215 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00004216 *
4217 * Quick display of a NodeSet
4218 */
4219void
4220xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4221 int i;
4222
4223 if (output == NULL) output = xmlGenericErrorContext;
4224 if (obj == NULL) {
4225 fprintf(output, "NodeSet == NULL !\n");
4226 return;
4227 }
4228 if (obj->nodeNr == 0) {
4229 fprintf(output, "NodeSet is empty\n");
4230 return;
4231 }
4232 if (obj->nodeTab == NULL) {
4233 fprintf(output, " nodeTab == NULL !\n");
4234 return;
4235 }
4236 for (i = 0; i < obj->nodeNr; i++) {
4237 if (obj->nodeTab[i] == NULL) {
4238 fprintf(output, " NULL !\n");
4239 return;
4240 }
4241 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4242 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4243 fprintf(output, " /");
4244 else if (obj->nodeTab[i]->name == NULL)
4245 fprintf(output, " noname!");
4246 else fprintf(output, " %s", obj->nodeTab[i]->name);
4247 }
4248 fprintf(output, "\n");
4249}
4250#endif
4251
4252/**
4253 * xmlXPathNewNodeSet:
4254 * @val: the NodePtr value
4255 *
4256 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4257 * it with the single Node @val
4258 *
4259 * Returns the newly created object.
4260 */
4261xmlXPathObjectPtr
4262xmlXPathNewNodeSet(xmlNodePtr val) {
4263 xmlXPathObjectPtr ret;
4264
4265 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4266 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004267 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004268 return(NULL);
4269 }
4270 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4271 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00004272 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004273 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00004274 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004275#ifdef XP_DEBUG_OBJ_USAGE
4276 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4277#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004278 return(ret);
4279}
4280
4281/**
4282 * xmlXPathNewValueTree:
4283 * @val: the NodePtr value
4284 *
4285 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4286 * it with the tree root @val
4287 *
4288 * Returns the newly created object.
4289 */
4290xmlXPathObjectPtr
4291xmlXPathNewValueTree(xmlNodePtr val) {
4292 xmlXPathObjectPtr ret;
4293
4294 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4295 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004296 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004297 return(NULL);
4298 }
4299 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4300 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00004301 ret->boolval = 1;
4302 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00004303 ret->nodesetval = xmlXPathNodeSetCreate(val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004304#ifdef XP_DEBUG_OBJ_USAGE
4305 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4306#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004307 return(ret);
4308}
4309
4310/**
4311 * xmlXPathNewNodeSetList:
4312 * @val: an existing NodeSet
4313 *
4314 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4315 * it with the Nodeset @val
4316 *
4317 * Returns the newly created object.
4318 */
4319xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004320xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4321{
Owen Taylor3473f882001-02-23 17:55:21 +00004322 xmlXPathObjectPtr ret;
4323 int i;
4324
4325 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004326 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00004327 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004328 ret = xmlXPathNewNodeSet(NULL);
4329 else {
4330 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004331 if (ret)
4332 for (i = 1; i < val->nodeNr; ++i)
4333 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004334 }
Owen Taylor3473f882001-02-23 17:55:21 +00004335
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004336 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004337}
4338
4339/**
4340 * xmlXPathWrapNodeSet:
4341 * @val: the NodePtr value
4342 *
4343 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4344 *
4345 * Returns the newly created object.
4346 */
4347xmlXPathObjectPtr
4348xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4349 xmlXPathObjectPtr ret;
4350
4351 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4352 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004353 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004354 return(NULL);
4355 }
4356 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4357 ret->type = XPATH_NODESET;
4358 ret->nodesetval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004359#ifdef XP_DEBUG_OBJ_USAGE
4360 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4361#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004362 return(ret);
4363}
4364
4365/**
4366 * xmlXPathFreeNodeSetList:
4367 * @obj: an existing NodeSetList object
4368 *
4369 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4370 * the list contrary to xmlXPathFreeObject().
4371 */
4372void
4373xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4374 if (obj == NULL) return;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004375#ifdef XP_DEBUG_OBJ_USAGE
4376 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4377#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004378 xmlFree(obj);
4379}
4380
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004381/**
4382 * xmlXPathDifference:
4383 * @nodes1: a node-set
4384 * @nodes2: a node-set
4385 *
4386 * Implements the EXSLT - Sets difference() function:
4387 * node-set set:difference (node-set, node-set)
4388 *
4389 * Returns the difference between the two node sets, or nodes1 if
4390 * nodes2 is empty
4391 */
4392xmlNodeSetPtr
4393xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4394 xmlNodeSetPtr ret;
4395 int i, l1;
4396 xmlNodePtr cur;
4397
4398 if (xmlXPathNodeSetIsEmpty(nodes2))
4399 return(nodes1);
4400
4401 ret = xmlXPathNodeSetCreate(NULL);
4402 if (xmlXPathNodeSetIsEmpty(nodes1))
4403 return(ret);
4404
4405 l1 = xmlXPathNodeSetGetLength(nodes1);
4406
4407 for (i = 0; i < l1; i++) {
4408 cur = xmlXPathNodeSetItem(nodes1, i);
4409 if (!xmlXPathNodeSetContains(nodes2, cur))
4410 xmlXPathNodeSetAddUnique(ret, cur);
4411 }
4412 return(ret);
4413}
4414
4415/**
4416 * xmlXPathIntersection:
4417 * @nodes1: a node-set
4418 * @nodes2: a node-set
4419 *
4420 * Implements the EXSLT - Sets intersection() function:
4421 * node-set set:intersection (node-set, node-set)
4422 *
4423 * Returns a node set comprising the nodes that are within both the
4424 * node sets passed as arguments
4425 */
4426xmlNodeSetPtr
4427xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4428 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4429 int i, l1;
4430 xmlNodePtr cur;
4431
Daniel Veillardf88d8492008-04-01 08:00:31 +00004432 if (ret == NULL)
4433 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004434 if (xmlXPathNodeSetIsEmpty(nodes1))
4435 return(ret);
4436 if (xmlXPathNodeSetIsEmpty(nodes2))
4437 return(ret);
4438
4439 l1 = xmlXPathNodeSetGetLength(nodes1);
4440
4441 for (i = 0; i < l1; i++) {
4442 cur = xmlXPathNodeSetItem(nodes1, i);
4443 if (xmlXPathNodeSetContains(nodes2, cur))
4444 xmlXPathNodeSetAddUnique(ret, cur);
4445 }
4446 return(ret);
4447}
4448
4449/**
4450 * xmlXPathDistinctSorted:
4451 * @nodes: a node-set, sorted by document order
4452 *
4453 * Implements the EXSLT - Sets distinct() function:
4454 * node-set set:distinct (node-set)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004455 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004456 * Returns a subset of the nodes contained in @nodes, or @nodes if
4457 * it is empty
4458 */
4459xmlNodeSetPtr
4460xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4461 xmlNodeSetPtr ret;
4462 xmlHashTablePtr hash;
4463 int i, l;
4464 xmlChar * strval;
4465 xmlNodePtr cur;
4466
4467 if (xmlXPathNodeSetIsEmpty(nodes))
4468 return(nodes);
4469
4470 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004471 if (ret == NULL)
4472 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004473 l = xmlXPathNodeSetGetLength(nodes);
4474 hash = xmlHashCreate (l);
4475 for (i = 0; i < l; i++) {
4476 cur = xmlXPathNodeSetItem(nodes, i);
4477 strval = xmlXPathCastNodeToString(cur);
4478 if (xmlHashLookup(hash, strval) == NULL) {
4479 xmlHashAddEntry(hash, strval, strval);
4480 xmlXPathNodeSetAddUnique(ret, cur);
4481 } else {
4482 xmlFree(strval);
4483 }
4484 }
4485 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4486 return(ret);
4487}
4488
4489/**
4490 * xmlXPathDistinct:
4491 * @nodes: a node-set
4492 *
4493 * Implements the EXSLT - Sets distinct() function:
4494 * node-set set:distinct (node-set)
4495 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4496 * is called with the sorted node-set
4497 *
4498 * Returns a subset of the nodes contained in @nodes, or @nodes if
4499 * it is empty
4500 */
4501xmlNodeSetPtr
4502xmlXPathDistinct (xmlNodeSetPtr nodes) {
4503 if (xmlXPathNodeSetIsEmpty(nodes))
4504 return(nodes);
4505
4506 xmlXPathNodeSetSort(nodes);
4507 return(xmlXPathDistinctSorted(nodes));
4508}
4509
4510/**
4511 * xmlXPathHasSameNodes:
4512 * @nodes1: a node-set
4513 * @nodes2: a node-set
4514 *
4515 * Implements the EXSLT - Sets has-same-nodes function:
4516 * boolean set:has-same-node(node-set, node-set)
4517 *
4518 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4519 * otherwise
4520 */
4521int
4522xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4523 int i, l;
4524 xmlNodePtr cur;
4525
4526 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4527 xmlXPathNodeSetIsEmpty(nodes2))
4528 return(0);
4529
4530 l = xmlXPathNodeSetGetLength(nodes1);
4531 for (i = 0; i < l; i++) {
4532 cur = xmlXPathNodeSetItem(nodes1, i);
4533 if (xmlXPathNodeSetContains(nodes2, cur))
4534 return(1);
4535 }
4536 return(0);
4537}
4538
4539/**
4540 * xmlXPathNodeLeadingSorted:
4541 * @nodes: a node-set, sorted by document order
4542 * @node: a node
4543 *
4544 * Implements the EXSLT - Sets leading() function:
4545 * node-set set:leading (node-set, node-set)
4546 *
4547 * Returns the nodes in @nodes that precede @node in document order,
4548 * @nodes if @node is NULL or an empty node-set if @nodes
4549 * doesn't contain @node
4550 */
4551xmlNodeSetPtr
4552xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4553 int i, l;
4554 xmlNodePtr cur;
4555 xmlNodeSetPtr ret;
4556
4557 if (node == NULL)
4558 return(nodes);
4559
4560 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004561 if (ret == NULL)
4562 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004563 if (xmlXPathNodeSetIsEmpty(nodes) ||
4564 (!xmlXPathNodeSetContains(nodes, node)))
4565 return(ret);
4566
4567 l = xmlXPathNodeSetGetLength(nodes);
4568 for (i = 0; i < l; i++) {
4569 cur = xmlXPathNodeSetItem(nodes, i);
4570 if (cur == node)
4571 break;
4572 xmlXPathNodeSetAddUnique(ret, cur);
4573 }
4574 return(ret);
4575}
4576
4577/**
4578 * xmlXPathNodeLeading:
4579 * @nodes: a node-set
4580 * @node: a node
4581 *
4582 * Implements the EXSLT - Sets leading() function:
4583 * node-set set:leading (node-set, node-set)
4584 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4585 * is called.
4586 *
4587 * Returns the nodes in @nodes that precede @node in document order,
4588 * @nodes if @node is NULL or an empty node-set if @nodes
4589 * doesn't contain @node
4590 */
4591xmlNodeSetPtr
4592xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4593 xmlXPathNodeSetSort(nodes);
4594 return(xmlXPathNodeLeadingSorted(nodes, node));
4595}
4596
4597/**
4598 * xmlXPathLeadingSorted:
4599 * @nodes1: a node-set, sorted by document order
4600 * @nodes2: a node-set, sorted by document order
4601 *
4602 * Implements the EXSLT - Sets leading() function:
4603 * node-set set:leading (node-set, node-set)
4604 *
4605 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4606 * in document order, @nodes1 if @nodes2 is NULL or empty or
4607 * an empty node-set if @nodes1 doesn't contain @nodes2
4608 */
4609xmlNodeSetPtr
4610xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4611 if (xmlXPathNodeSetIsEmpty(nodes2))
4612 return(nodes1);
4613 return(xmlXPathNodeLeadingSorted(nodes1,
4614 xmlXPathNodeSetItem(nodes2, 1)));
4615}
4616
4617/**
4618 * xmlXPathLeading:
4619 * @nodes1: a node-set
4620 * @nodes2: a node-set
4621 *
4622 * Implements the EXSLT - Sets leading() function:
4623 * node-set set:leading (node-set, node-set)
4624 * @nodes1 and @nodes2 are sorted by document order, then
4625 * #exslSetsLeadingSorted is called.
4626 *
4627 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4628 * in document order, @nodes1 if @nodes2 is NULL or empty or
4629 * an empty node-set if @nodes1 doesn't contain @nodes2
4630 */
4631xmlNodeSetPtr
4632xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4633 if (xmlXPathNodeSetIsEmpty(nodes2))
4634 return(nodes1);
4635 if (xmlXPathNodeSetIsEmpty(nodes1))
4636 return(xmlXPathNodeSetCreate(NULL));
4637 xmlXPathNodeSetSort(nodes1);
4638 xmlXPathNodeSetSort(nodes2);
4639 return(xmlXPathNodeLeadingSorted(nodes1,
4640 xmlXPathNodeSetItem(nodes2, 1)));
4641}
4642
4643/**
4644 * xmlXPathNodeTrailingSorted:
4645 * @nodes: a node-set, sorted by document order
4646 * @node: a node
4647 *
4648 * Implements the EXSLT - Sets trailing() function:
4649 * node-set set:trailing (node-set, node-set)
4650 *
4651 * Returns the nodes in @nodes that follow @node in document order,
4652 * @nodes if @node is NULL or an empty node-set if @nodes
4653 * doesn't contain @node
4654 */
4655xmlNodeSetPtr
4656xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4657 int i, l;
4658 xmlNodePtr cur;
4659 xmlNodeSetPtr ret;
4660
4661 if (node == NULL)
4662 return(nodes);
4663
4664 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004665 if (ret == NULL)
4666 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004667 if (xmlXPathNodeSetIsEmpty(nodes) ||
4668 (!xmlXPathNodeSetContains(nodes, node)))
4669 return(ret);
4670
4671 l = xmlXPathNodeSetGetLength(nodes);
William M. Brack97ac8192007-06-06 17:19:24 +00004672 for (i = l - 1; i >= 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004673 cur = xmlXPathNodeSetItem(nodes, i);
4674 if (cur == node)
4675 break;
4676 xmlXPathNodeSetAddUnique(ret, cur);
4677 }
William M. Brack97ac8192007-06-06 17:19:24 +00004678 xmlXPathNodeSetSort(ret); /* bug 413451 */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004679 return(ret);
4680}
4681
4682/**
4683 * xmlXPathNodeTrailing:
4684 * @nodes: a node-set
4685 * @node: a node
4686 *
4687 * Implements the EXSLT - Sets trailing() function:
4688 * node-set set:trailing (node-set, node-set)
4689 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4690 * is called.
4691 *
4692 * Returns the nodes in @nodes that follow @node in document order,
4693 * @nodes if @node is NULL or an empty node-set if @nodes
4694 * doesn't contain @node
4695 */
4696xmlNodeSetPtr
4697xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4698 xmlXPathNodeSetSort(nodes);
4699 return(xmlXPathNodeTrailingSorted(nodes, node));
4700}
4701
4702/**
4703 * xmlXPathTrailingSorted:
4704 * @nodes1: a node-set, sorted by document order
4705 * @nodes2: a node-set, sorted by document order
4706 *
4707 * Implements the EXSLT - Sets trailing() function:
4708 * node-set set:trailing (node-set, node-set)
4709 *
4710 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4711 * in document order, @nodes1 if @nodes2 is NULL or empty or
4712 * an empty node-set if @nodes1 doesn't contain @nodes2
4713 */
4714xmlNodeSetPtr
4715xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4716 if (xmlXPathNodeSetIsEmpty(nodes2))
4717 return(nodes1);
4718 return(xmlXPathNodeTrailingSorted(nodes1,
4719 xmlXPathNodeSetItem(nodes2, 0)));
4720}
4721
4722/**
4723 * xmlXPathTrailing:
4724 * @nodes1: a node-set
4725 * @nodes2: a node-set
4726 *
4727 * Implements the EXSLT - Sets trailing() function:
4728 * node-set set:trailing (node-set, node-set)
4729 * @nodes1 and @nodes2 are sorted by document order, then
4730 * #xmlXPathTrailingSorted is called.
4731 *
4732 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4733 * in document order, @nodes1 if @nodes2 is NULL or empty or
4734 * an empty node-set if @nodes1 doesn't contain @nodes2
4735 */
4736xmlNodeSetPtr
4737xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4738 if (xmlXPathNodeSetIsEmpty(nodes2))
4739 return(nodes1);
4740 if (xmlXPathNodeSetIsEmpty(nodes1))
4741 return(xmlXPathNodeSetCreate(NULL));
4742 xmlXPathNodeSetSort(nodes1);
4743 xmlXPathNodeSetSort(nodes2);
4744 return(xmlXPathNodeTrailingSorted(nodes1,
4745 xmlXPathNodeSetItem(nodes2, 0)));
4746}
4747
Owen Taylor3473f882001-02-23 17:55:21 +00004748/************************************************************************
4749 * *
4750 * Routines to handle extra functions *
4751 * *
4752 ************************************************************************/
4753
4754/**
4755 * xmlXPathRegisterFunc:
4756 * @ctxt: the XPath context
4757 * @name: the function name
4758 * @f: the function implementation or NULL
4759 *
4760 * Register a new function. If @f is NULL it unregisters the function
4761 *
4762 * Returns 0 in case of success, -1 in case of error
4763 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00004764int
Owen Taylor3473f882001-02-23 17:55:21 +00004765xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4766 xmlXPathFunction f) {
4767 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4768}
4769
4770/**
4771 * xmlXPathRegisterFuncNS:
4772 * @ctxt: the XPath context
4773 * @name: the function name
4774 * @ns_uri: the function namespace URI
4775 * @f: the function implementation or NULL
4776 *
4777 * Register a new function. If @f is NULL it unregisters the function
4778 *
4779 * Returns 0 in case of success, -1 in case of error
4780 */
4781int
4782xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4783 const xmlChar *ns_uri, xmlXPathFunction f) {
4784 if (ctxt == NULL)
4785 return(-1);
4786 if (name == NULL)
4787 return(-1);
4788
4789 if (ctxt->funcHash == NULL)
4790 ctxt->funcHash = xmlHashCreate(0);
4791 if (ctxt->funcHash == NULL)
4792 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004793 if (f == NULL)
4794 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
William M. Brackad0e67c2004-12-01 14:35:10 +00004795 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
Owen Taylor3473f882001-02-23 17:55:21 +00004796}
4797
4798/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00004799 * xmlXPathRegisterFuncLookup:
4800 * @ctxt: the XPath context
4801 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004802 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00004803 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004804 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00004805 */
4806void
4807xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4808 xmlXPathFuncLookupFunc f,
4809 void *funcCtxt) {
4810 if (ctxt == NULL)
4811 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004812 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004813 ctxt->funcLookupData = funcCtxt;
4814}
4815
4816/**
Owen Taylor3473f882001-02-23 17:55:21 +00004817 * xmlXPathFunctionLookup:
4818 * @ctxt: the XPath context
4819 * @name: the function name
4820 *
4821 * Search in the Function array of the context for the given
4822 * function.
4823 *
4824 * Returns the xmlXPathFunction or NULL if not found
4825 */
4826xmlXPathFunction
4827xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00004828 if (ctxt == NULL)
4829 return (NULL);
4830
4831 if (ctxt->funcLookupFunc != NULL) {
4832 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004833 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004834
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004835 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004836 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004837 if (ret != NULL)
4838 return(ret);
4839 }
Owen Taylor3473f882001-02-23 17:55:21 +00004840 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4841}
4842
4843/**
4844 * xmlXPathFunctionLookupNS:
4845 * @ctxt: the XPath context
4846 * @name: the function name
4847 * @ns_uri: the function namespace URI
4848 *
4849 * Search in the Function array of the context for the given
4850 * function.
4851 *
4852 * Returns the xmlXPathFunction or NULL if not found
4853 */
4854xmlXPathFunction
4855xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4856 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00004857 xmlXPathFunction ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004858
Owen Taylor3473f882001-02-23 17:55:21 +00004859 if (ctxt == NULL)
4860 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004861 if (name == NULL)
4862 return(NULL);
4863
Thomas Broyerba4ad322001-07-26 16:55:21 +00004864 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004865 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004866
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004867 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004868 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004869 if (ret != NULL)
4870 return(ret);
4871 }
4872
4873 if (ctxt->funcHash == NULL)
4874 return(NULL);
4875
William M. Brackad0e67c2004-12-01 14:35:10 +00004876 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4877 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004878}
4879
4880/**
4881 * xmlXPathRegisteredFuncsCleanup:
4882 * @ctxt: the XPath context
4883 *
4884 * Cleanup the XPath context data associated to registered functions
4885 */
4886void
4887xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4888 if (ctxt == NULL)
4889 return;
4890
4891 xmlHashFree(ctxt->funcHash, NULL);
4892 ctxt->funcHash = NULL;
4893}
4894
4895/************************************************************************
4896 * *
William M. Brack08171912003-12-29 02:52:11 +00004897 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00004898 * *
4899 ************************************************************************/
4900
4901/**
4902 * xmlXPathRegisterVariable:
4903 * @ctxt: the XPath context
4904 * @name: the variable name
4905 * @value: the variable value or NULL
4906 *
4907 * Register a new variable value. If @value is NULL it unregisters
4908 * the variable
4909 *
4910 * Returns 0 in case of success, -1 in case of error
4911 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00004912int
Owen Taylor3473f882001-02-23 17:55:21 +00004913xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4914 xmlXPathObjectPtr value) {
4915 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4916}
4917
4918/**
4919 * xmlXPathRegisterVariableNS:
4920 * @ctxt: the XPath context
4921 * @name: the variable name
4922 * @ns_uri: the variable namespace URI
4923 * @value: the variable value or NULL
4924 *
4925 * Register a new variable value. If @value is NULL it unregisters
4926 * the variable
4927 *
4928 * Returns 0 in case of success, -1 in case of error
4929 */
4930int
4931xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4932 const xmlChar *ns_uri,
4933 xmlXPathObjectPtr value) {
4934 if (ctxt == NULL)
4935 return(-1);
4936 if (name == NULL)
4937 return(-1);
4938
4939 if (ctxt->varHash == NULL)
4940 ctxt->varHash = xmlHashCreate(0);
4941 if (ctxt->varHash == NULL)
4942 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004943 if (value == NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004944 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
Daniel Veillard94394cd2003-10-29 17:07:51 +00004945 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00004946 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4947 (void *) value,
4948 (xmlHashDeallocator)xmlXPathFreeObject));
4949}
4950
4951/**
4952 * xmlXPathRegisterVariableLookup:
4953 * @ctxt: the XPath context
4954 * @f: the lookup function
4955 * @data: the lookup data
4956 *
4957 * register an external mechanism to do variable lookup
4958 */
4959void
4960xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4961 xmlXPathVariableLookupFunc f, void *data) {
4962 if (ctxt == NULL)
4963 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004964 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00004965 ctxt->varLookupData = data;
4966}
4967
4968/**
4969 * xmlXPathVariableLookup:
4970 * @ctxt: the XPath context
4971 * @name: the variable name
4972 *
4973 * Search in the Variable array of the context for the given
4974 * variable value.
4975 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00004976 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00004977 */
4978xmlXPathObjectPtr
4979xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4980 if (ctxt == NULL)
4981 return(NULL);
4982
4983 if (ctxt->varLookupFunc != NULL) {
4984 xmlXPathObjectPtr ret;
4985
4986 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4987 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00004988 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004989 }
4990 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4991}
4992
4993/**
4994 * xmlXPathVariableLookupNS:
4995 * @ctxt: the XPath context
4996 * @name: the variable name
4997 * @ns_uri: the variable namespace URI
4998 *
4999 * Search in the Variable array of the context for the given
Daniel Veillard45490ae2008-07-29 09:13:19 +00005000 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00005001 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00005002 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00005003 */
5004xmlXPathObjectPtr
5005xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5006 const xmlChar *ns_uri) {
5007 if (ctxt == NULL)
5008 return(NULL);
5009
5010 if (ctxt->varLookupFunc != NULL) {
5011 xmlXPathObjectPtr ret;
5012
5013 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5014 (ctxt->varLookupData, name, ns_uri);
5015 if (ret != NULL) return(ret);
5016 }
5017
5018 if (ctxt->varHash == NULL)
5019 return(NULL);
5020 if (name == NULL)
5021 return(NULL);
5022
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005023 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
Daniel Veillard8c357d52001-07-03 23:43:33 +00005024 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00005025}
5026
5027/**
5028 * xmlXPathRegisteredVariablesCleanup:
5029 * @ctxt: the XPath context
5030 *
5031 * Cleanup the XPath context data associated to registered variables
5032 */
5033void
5034xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5035 if (ctxt == NULL)
5036 return;
5037
Daniel Veillard76d66f42001-05-16 21:05:17 +00005038 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00005039 ctxt->varHash = NULL;
5040}
5041
5042/**
5043 * xmlXPathRegisterNs:
5044 * @ctxt: the XPath context
Daniel Veillarddb3ce962009-03-25 09:43:49 +00005045 * @prefix: the namespace prefix cannot be NULL or empty string
Owen Taylor3473f882001-02-23 17:55:21 +00005046 * @ns_uri: the namespace name
5047 *
5048 * Register a new namespace. If @ns_uri is NULL it unregisters
5049 * the namespace
5050 *
5051 * Returns 0 in case of success, -1 in case of error
5052 */
5053int
5054xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5055 const xmlChar *ns_uri) {
5056 if (ctxt == NULL)
5057 return(-1);
5058 if (prefix == NULL)
5059 return(-1);
Daniel Veillarddb3ce962009-03-25 09:43:49 +00005060 if (prefix[0] == 0)
5061 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00005062
5063 if (ctxt->nsHash == NULL)
5064 ctxt->nsHash = xmlHashCreate(10);
5065 if (ctxt->nsHash == NULL)
5066 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00005067 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00005068 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00005069 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00005070 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00005071 (xmlHashDeallocator)xmlFree));
5072}
5073
5074/**
5075 * xmlXPathNsLookup:
5076 * @ctxt: the XPath context
5077 * @prefix: the namespace prefix value
5078 *
5079 * Search in the namespace declaration array of the context for the given
5080 * namespace name associated to the given prefix
5081 *
5082 * Returns the value or NULL if not found
5083 */
5084const xmlChar *
5085xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5086 if (ctxt == NULL)
5087 return(NULL);
5088 if (prefix == NULL)
5089 return(NULL);
5090
5091#ifdef XML_XML_NAMESPACE
5092 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5093 return(XML_XML_NAMESPACE);
5094#endif
5095
Daniel Veillardc8f620b2001-04-30 20:31:33 +00005096 if (ctxt->namespaces != NULL) {
5097 int i;
5098
5099 for (i = 0;i < ctxt->nsNr;i++) {
5100 if ((ctxt->namespaces[i] != NULL) &&
5101 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5102 return(ctxt->namespaces[i]->href);
5103 }
5104 }
Owen Taylor3473f882001-02-23 17:55:21 +00005105
5106 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5107}
5108
5109/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005110 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00005111 * @ctxt: the XPath context
5112 *
5113 * Cleanup the XPath context data associated to registered variables
5114 */
5115void
5116xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5117 if (ctxt == NULL)
5118 return;
5119
Daniel Veillard42766c02002-08-22 20:52:17 +00005120 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00005121 ctxt->nsHash = NULL;
5122}
5123
5124/************************************************************************
5125 * *
5126 * Routines to handle Values *
5127 * *
5128 ************************************************************************/
5129
William M. Brack08171912003-12-29 02:52:11 +00005130/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005131
5132/**
5133 * xmlXPathNewFloat:
5134 * @val: the double value
5135 *
5136 * Create a new xmlXPathObjectPtr of type double and of value @val
5137 *
5138 * Returns the newly created object.
5139 */
5140xmlXPathObjectPtr
5141xmlXPathNewFloat(double val) {
5142 xmlXPathObjectPtr ret;
5143
5144 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5145 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005146 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005147 return(NULL);
5148 }
5149 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5150 ret->type = XPATH_NUMBER;
5151 ret->floatval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005152#ifdef XP_DEBUG_OBJ_USAGE
5153 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5154#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005155 return(ret);
5156}
5157
5158/**
5159 * xmlXPathNewBoolean:
5160 * @val: the boolean value
5161 *
5162 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5163 *
5164 * Returns the newly created object.
5165 */
5166xmlXPathObjectPtr
5167xmlXPathNewBoolean(int val) {
5168 xmlXPathObjectPtr ret;
5169
5170 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5171 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005172 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005173 return(NULL);
5174 }
5175 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5176 ret->type = XPATH_BOOLEAN;
5177 ret->boolval = (val != 0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005178#ifdef XP_DEBUG_OBJ_USAGE
5179 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5180#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005181 return(ret);
5182}
5183
5184/**
5185 * xmlXPathNewString:
5186 * @val: the xmlChar * value
5187 *
5188 * Create a new xmlXPathObjectPtr of type string and of value @val
5189 *
5190 * Returns the newly created object.
5191 */
5192xmlXPathObjectPtr
5193xmlXPathNewString(const xmlChar *val) {
5194 xmlXPathObjectPtr ret;
5195
5196 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5197 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005198 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005199 return(NULL);
5200 }
5201 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5202 ret->type = XPATH_STRING;
5203 if (val != NULL)
5204 ret->stringval = xmlStrdup(val);
5205 else
5206 ret->stringval = xmlStrdup((const xmlChar *)"");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005207#ifdef XP_DEBUG_OBJ_USAGE
5208 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5209#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005210 return(ret);
5211}
5212
5213/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005214 * xmlXPathWrapString:
5215 * @val: the xmlChar * value
5216 *
5217 * Wraps the @val string into an XPath object.
5218 *
5219 * Returns the newly created object.
5220 */
5221xmlXPathObjectPtr
5222xmlXPathWrapString (xmlChar *val) {
5223 xmlXPathObjectPtr ret;
5224
5225 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5226 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005227 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005228 return(NULL);
5229 }
5230 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5231 ret->type = XPATH_STRING;
5232 ret->stringval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005233#ifdef XP_DEBUG_OBJ_USAGE
5234 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5235#endif
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005236 return(ret);
5237}
5238
5239/**
Owen Taylor3473f882001-02-23 17:55:21 +00005240 * xmlXPathNewCString:
5241 * @val: the char * value
5242 *
5243 * Create a new xmlXPathObjectPtr of type string and of value @val
5244 *
5245 * Returns the newly created object.
5246 */
5247xmlXPathObjectPtr
5248xmlXPathNewCString(const char *val) {
5249 xmlXPathObjectPtr ret;
5250
5251 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5252 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005253 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005254 return(NULL);
5255 }
5256 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5257 ret->type = XPATH_STRING;
5258 ret->stringval = xmlStrdup(BAD_CAST val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005259#ifdef XP_DEBUG_OBJ_USAGE
5260 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5261#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005262 return(ret);
5263}
5264
5265/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005266 * xmlXPathWrapCString:
5267 * @val: the char * value
5268 *
5269 * Wraps a string into an XPath object.
5270 *
5271 * Returns the newly created object.
5272 */
5273xmlXPathObjectPtr
5274xmlXPathWrapCString (char * val) {
5275 return(xmlXPathWrapString((xmlChar *)(val)));
5276}
5277
5278/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005279 * xmlXPathWrapExternal:
5280 * @val: the user data
5281 *
5282 * Wraps the @val data into an XPath object.
5283 *
5284 * Returns the newly created object.
5285 */
5286xmlXPathObjectPtr
5287xmlXPathWrapExternal (void *val) {
5288 xmlXPathObjectPtr ret;
5289
5290 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5291 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005292 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005293 return(NULL);
5294 }
5295 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5296 ret->type = XPATH_USERS;
5297 ret->user = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005298#ifdef XP_DEBUG_OBJ_USAGE
5299 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5300#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005301 return(ret);
5302}
5303
5304/**
Owen Taylor3473f882001-02-23 17:55:21 +00005305 * xmlXPathObjectCopy:
5306 * @val: the original object
5307 *
5308 * allocate a new copy of a given object
5309 *
5310 * Returns the newly created object.
5311 */
5312xmlXPathObjectPtr
5313xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5314 xmlXPathObjectPtr ret;
5315
5316 if (val == NULL)
5317 return(NULL);
5318
5319 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5320 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005321 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005322 return(NULL);
5323 }
5324 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005325#ifdef XP_DEBUG_OBJ_USAGE
5326 xmlXPathDebugObjUsageRequested(NULL, val->type);
5327#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005328 switch (val->type) {
5329 case XPATH_BOOLEAN:
5330 case XPATH_NUMBER:
5331 case XPATH_POINT:
5332 case XPATH_RANGE:
5333 break;
5334 case XPATH_STRING:
5335 ret->stringval = xmlStrdup(val->stringval);
5336 break;
5337 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00005338#if 0
5339/*
5340 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5341 this previous handling is no longer correct, and can cause some serious
5342 problems (ref. bug 145547)
5343*/
Owen Taylor3473f882001-02-23 17:55:21 +00005344 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005345 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005346 xmlNodePtr cur, tmp;
5347 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005348
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005349 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005350 top = xmlNewDoc(NULL);
5351 top->name = (char *)
5352 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005353 ret->user = top;
5354 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005355 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005356 cur = val->nodesetval->nodeTab[0]->children;
5357 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005358 tmp = xmlDocCopyNode(cur, top, 1);
5359 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005360 cur = cur->next;
5361 }
5362 }
William M. Bracke9449c52004-07-11 14:41:20 +00005363
Daniel Veillard9adc0462003-03-24 18:39:54 +00005364 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005365 } else
Owen Taylor3473f882001-02-23 17:55:21 +00005366 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005367 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00005368 break;
William M. Bracke9449c52004-07-11 14:41:20 +00005369#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005370 case XPATH_NODESET:
5371 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005372 /* Do not deallocate the copied tree value */
5373 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005374 break;
5375 case XPATH_LOCATIONSET:
5376#ifdef LIBXML_XPTR_ENABLED
5377 {
5378 xmlLocationSetPtr loc = val->user;
5379 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5380 break;
5381 }
5382#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00005383 case XPATH_USERS:
5384 ret->user = val->user;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005385 break;
Thomas Broyer47334c02001-10-07 16:41:52 +00005386 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00005387 xmlGenericError(xmlGenericErrorContext,
5388 "xmlXPathObjectCopy: unsupported type %d\n",
5389 val->type);
5390 break;
5391 }
5392 return(ret);
5393}
5394
5395/**
5396 * xmlXPathFreeObject:
5397 * @obj: the object to free
5398 *
5399 * Free up an xmlXPathObjectPtr object.
5400 */
5401void
5402xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5403 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005404 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00005405 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00005406#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005407 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005408 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00005409 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00005410 } else
5411#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005412 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
William M. Bracke9449c52004-07-11 14:41:20 +00005413 if (obj->nodesetval != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00005414 xmlXPathFreeValueTree(obj->nodesetval);
Daniel Veillard77851712001-02-27 21:54:07 +00005415 } else {
5416 if (obj->nodesetval != NULL)
5417 xmlXPathFreeNodeSet(obj->nodesetval);
5418 }
Owen Taylor3473f882001-02-23 17:55:21 +00005419#ifdef LIBXML_XPTR_ENABLED
5420 } else if (obj->type == XPATH_LOCATIONSET) {
5421 if (obj->user != NULL)
5422 xmlXPtrFreeLocationSet(obj->user);
5423#endif
5424 } else if (obj->type == XPATH_STRING) {
5425 if (obj->stringval != NULL)
5426 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005427 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005428#ifdef XP_DEBUG_OBJ_USAGE
5429 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5430#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00005431 xmlFree(obj);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005432}
Owen Taylor3473f882001-02-23 17:55:21 +00005433
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005434/**
5435 * xmlXPathReleaseObject:
5436 * @obj: the xmlXPathObjectPtr to free or to cache
5437 *
5438 * Depending on the state of the cache this frees the given
5439 * XPath object or stores it in the cache.
5440 */
5441static void
5442xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5443{
5444#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5445 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5446 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5447
5448#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5449
5450 if (obj == NULL)
5451 return;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005452 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005453 xmlXPathFreeObject(obj);
Daniel Veillard45490ae2008-07-29 09:13:19 +00005454 } else {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005455 xmlXPathContextCachePtr cache =
5456 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005457
5458 switch (obj->type) {
5459 case XPATH_NODESET:
5460 case XPATH_XSLT_TREE:
5461 if (obj->nodesetval != NULL) {
5462 if (obj->boolval) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00005463 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005464 * It looks like the @boolval is used for
5465 * evaluation if this an XSLT Result Tree Fragment.
5466 * TODO: Check if this assumption is correct.
5467 */
5468 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5469 xmlXPathFreeValueTree(obj->nodesetval);
5470 obj->nodesetval = NULL;
5471 } else if ((obj->nodesetval->nodeMax <= 40) &&
5472 (XP_CACHE_WANTS(cache->nodesetObjs,
5473 cache->maxNodeset)))
5474 {
5475 XP_CACHE_ADD(cache->nodesetObjs, obj);
5476 goto obj_cached;
5477 } else {
5478 xmlXPathFreeNodeSet(obj->nodesetval);
5479 obj->nodesetval = NULL;
5480 }
5481 }
5482 break;
5483 case XPATH_STRING:
5484 if (obj->stringval != NULL)
5485 xmlFree(obj->stringval);
5486
5487 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5488 XP_CACHE_ADD(cache->stringObjs, obj);
5489 goto obj_cached;
5490 }
5491 break;
5492 case XPATH_BOOLEAN:
5493 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5494 XP_CACHE_ADD(cache->booleanObjs, obj);
5495 goto obj_cached;
5496 }
5497 break;
5498 case XPATH_NUMBER:
5499 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5500 XP_CACHE_ADD(cache->numberObjs, obj);
5501 goto obj_cached;
5502 }
5503 break;
5504#ifdef LIBXML_XPTR_ENABLED
5505 case XPATH_LOCATIONSET:
5506 if (obj->user != NULL) {
5507 xmlXPtrFreeLocationSet(obj->user);
5508 }
5509 goto free_obj;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005510#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005511 default:
5512 goto free_obj;
5513 }
5514
5515 /*
5516 * Fallback to adding to the misc-objects slot.
5517 */
5518 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5519 XP_CACHE_ADD(cache->miscObjs, obj);
5520 } else
5521 goto free_obj;
5522
5523obj_cached:
5524
5525#ifdef XP_DEBUG_OBJ_USAGE
5526 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5527#endif
5528
5529 if (obj->nodesetval != NULL) {
5530 xmlNodeSetPtr tmpset = obj->nodesetval;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005531
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005532 /*
5533 * TODO: Due to those nasty ns-nodes, we need to traverse
5534 * the list and free the ns-nodes.
5535 * URGENT TODO: Check if it's actually slowing things down.
5536 * Maybe we shouldn't try to preserve the list.
5537 */
5538 if (tmpset->nodeNr > 1) {
5539 int i;
5540 xmlNodePtr node;
5541
5542 for (i = 0; i < tmpset->nodeNr; i++) {
5543 node = tmpset->nodeTab[i];
5544 if ((node != NULL) &&
5545 (node->type == XML_NAMESPACE_DECL))
5546 {
5547 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5548 }
5549 }
5550 } else if (tmpset->nodeNr == 1) {
5551 if ((tmpset->nodeTab[0] != NULL) &&
5552 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5553 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
Daniel Veillard45490ae2008-07-29 09:13:19 +00005554 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005555 tmpset->nodeNr = 0;
5556 memset(obj, 0, sizeof(xmlXPathObject));
5557 obj->nodesetval = tmpset;
5558 } else
5559 memset(obj, 0, sizeof(xmlXPathObject));
5560
5561 return;
5562
5563free_obj:
5564 /*
5565 * Cache is full; free the object.
Daniel Veillard45490ae2008-07-29 09:13:19 +00005566 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005567 if (obj->nodesetval != NULL)
5568 xmlXPathFreeNodeSet(obj->nodesetval);
5569#ifdef XP_DEBUG_OBJ_USAGE
5570 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5571#endif
5572 xmlFree(obj);
5573 }
5574 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005575}
5576
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005577
5578/************************************************************************
5579 * *
5580 * Type Casting Routines *
5581 * *
5582 ************************************************************************/
5583
5584/**
5585 * xmlXPathCastBooleanToString:
5586 * @val: a boolean
5587 *
5588 * Converts a boolean to its string value.
5589 *
5590 * Returns a newly allocated string.
5591 */
5592xmlChar *
5593xmlXPathCastBooleanToString (int val) {
5594 xmlChar *ret;
5595 if (val)
5596 ret = xmlStrdup((const xmlChar *) "true");
5597 else
5598 ret = xmlStrdup((const xmlChar *) "false");
5599 return(ret);
5600}
5601
5602/**
5603 * xmlXPathCastNumberToString:
5604 * @val: a number
5605 *
5606 * Converts a number to its string value.
5607 *
5608 * Returns a newly allocated string.
5609 */
5610xmlChar *
5611xmlXPathCastNumberToString (double val) {
5612 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00005613 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005614 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005615 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005616 break;
5617 case -1:
5618 ret = xmlStrdup((const xmlChar *) "-Infinity");
5619 break;
5620 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00005621 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005622 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005623 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5624 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005625 } else {
5626 /* could be improved */
5627 char buf[100];
Daniel Veillard11ce4002006-03-10 00:36:23 +00005628 xmlXPathFormatNumber(val, buf, 99);
5629 buf[99] = 0;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005630 ret = xmlStrdup((const xmlChar *) buf);
5631 }
5632 }
5633 return(ret);
5634}
5635
5636/**
5637 * xmlXPathCastNodeToString:
5638 * @node: a node
5639 *
5640 * Converts a node to its string value.
5641 *
5642 * Returns a newly allocated string.
5643 */
5644xmlChar *
5645xmlXPathCastNodeToString (xmlNodePtr node) {
William M. Brackd611c882007-05-31 05:07:17 +00005646xmlChar *ret;
5647 if ((ret = xmlNodeGetContent(node)) == NULL)
5648 ret = xmlStrdup((const xmlChar *) "");
5649 return(ret);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005650}
5651
5652/**
5653 * xmlXPathCastNodeSetToString:
5654 * @ns: a node-set
5655 *
5656 * Converts a node-set to its string value.
5657 *
5658 * Returns a newly allocated string.
5659 */
5660xmlChar *
5661xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5662 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5663 return(xmlStrdup((const xmlChar *) ""));
5664
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00005665 if (ns->nodeNr > 1)
5666 xmlXPathNodeSetSort(ns);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005667 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5668}
5669
5670/**
5671 * xmlXPathCastToString:
5672 * @val: an XPath object
5673 *
5674 * Converts an existing object to its string() equivalent
5675 *
Kasimier T. Buchcik50128ad2006-08-15 13:04:07 +00005676 * Returns the allocated string value of the object, NULL in case of error.
Daniel Veillard45490ae2008-07-29 09:13:19 +00005677 * It's up to the caller to free the string memory with xmlFree().
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005678 */
5679xmlChar *
5680xmlXPathCastToString(xmlXPathObjectPtr val) {
5681 xmlChar *ret = NULL;
5682
5683 if (val == NULL)
5684 return(xmlStrdup((const xmlChar *) ""));
5685 switch (val->type) {
5686 case XPATH_UNDEFINED:
5687#ifdef DEBUG_EXPR
5688 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5689#endif
5690 ret = xmlStrdup((const xmlChar *) "");
5691 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005692 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005693 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005694 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5695 break;
5696 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00005697 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005698 case XPATH_BOOLEAN:
5699 ret = xmlXPathCastBooleanToString(val->boolval);
5700 break;
5701 case XPATH_NUMBER: {
5702 ret = xmlXPathCastNumberToString(val->floatval);
5703 break;
5704 }
5705 case XPATH_USERS:
5706 case XPATH_POINT:
5707 case XPATH_RANGE:
5708 case XPATH_LOCATIONSET:
5709 TODO
5710 ret = xmlStrdup((const xmlChar *) "");
5711 break;
5712 }
5713 return(ret);
5714}
5715
5716/**
5717 * xmlXPathConvertString:
5718 * @val: an XPath object
5719 *
5720 * Converts an existing object to its string() equivalent
5721 *
5722 * Returns the new object, the old one is freed (or the operation
5723 * is done directly on @val)
5724 */
5725xmlXPathObjectPtr
5726xmlXPathConvertString(xmlXPathObjectPtr val) {
5727 xmlChar *res = NULL;
5728
5729 if (val == NULL)
5730 return(xmlXPathNewCString(""));
5731
5732 switch (val->type) {
5733 case XPATH_UNDEFINED:
5734#ifdef DEBUG_EXPR
5735 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5736#endif
5737 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005738 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005739 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005740 res = xmlXPathCastNodeSetToString(val->nodesetval);
5741 break;
5742 case XPATH_STRING:
5743 return(val);
5744 case XPATH_BOOLEAN:
5745 res = xmlXPathCastBooleanToString(val->boolval);
5746 break;
5747 case XPATH_NUMBER:
5748 res = xmlXPathCastNumberToString(val->floatval);
5749 break;
5750 case XPATH_USERS:
5751 case XPATH_POINT:
5752 case XPATH_RANGE:
5753 case XPATH_LOCATIONSET:
5754 TODO;
5755 break;
5756 }
5757 xmlXPathFreeObject(val);
5758 if (res == NULL)
5759 return(xmlXPathNewCString(""));
5760 return(xmlXPathWrapString(res));
5761}
5762
5763/**
5764 * xmlXPathCastBooleanToNumber:
5765 * @val: a boolean
5766 *
5767 * Converts a boolean to its number value
5768 *
5769 * Returns the number value
5770 */
5771double
5772xmlXPathCastBooleanToNumber(int val) {
5773 if (val)
5774 return(1.0);
5775 return(0.0);
5776}
5777
5778/**
5779 * xmlXPathCastStringToNumber:
5780 * @val: a string
5781 *
5782 * Converts a string to its number value
5783 *
5784 * Returns the number value
5785 */
5786double
5787xmlXPathCastStringToNumber(const xmlChar * val) {
5788 return(xmlXPathStringEvalNumber(val));
5789}
5790
5791/**
5792 * xmlXPathCastNodeToNumber:
5793 * @node: a node
5794 *
5795 * Converts a node to its number value
5796 *
5797 * Returns the number value
5798 */
5799double
5800xmlXPathCastNodeToNumber (xmlNodePtr node) {
5801 xmlChar *strval;
5802 double ret;
5803
5804 if (node == NULL)
5805 return(xmlXPathNAN);
5806 strval = xmlXPathCastNodeToString(node);
5807 if (strval == NULL)
5808 return(xmlXPathNAN);
5809 ret = xmlXPathCastStringToNumber(strval);
5810 xmlFree(strval);
5811
5812 return(ret);
5813}
5814
5815/**
5816 * xmlXPathCastNodeSetToNumber:
5817 * @ns: a node-set
5818 *
5819 * Converts a node-set to its number value
5820 *
5821 * Returns the number value
5822 */
5823double
5824xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5825 xmlChar *str;
5826 double ret;
5827
5828 if (ns == NULL)
5829 return(xmlXPathNAN);
5830 str = xmlXPathCastNodeSetToString(ns);
5831 ret = xmlXPathCastStringToNumber(str);
5832 xmlFree(str);
5833 return(ret);
5834}
5835
5836/**
5837 * xmlXPathCastToNumber:
5838 * @val: an XPath object
5839 *
5840 * Converts an XPath object to its number value
5841 *
5842 * Returns the number value
5843 */
5844double
5845xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5846 double ret = 0.0;
5847
5848 if (val == NULL)
5849 return(xmlXPathNAN);
5850 switch (val->type) {
5851 case XPATH_UNDEFINED:
5852#ifdef DEGUB_EXPR
5853 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5854#endif
5855 ret = xmlXPathNAN;
5856 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005857 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005858 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005859 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5860 break;
5861 case XPATH_STRING:
5862 ret = xmlXPathCastStringToNumber(val->stringval);
5863 break;
5864 case XPATH_NUMBER:
5865 ret = val->floatval;
5866 break;
5867 case XPATH_BOOLEAN:
5868 ret = xmlXPathCastBooleanToNumber(val->boolval);
5869 break;
5870 case XPATH_USERS:
5871 case XPATH_POINT:
5872 case XPATH_RANGE:
5873 case XPATH_LOCATIONSET:
5874 TODO;
5875 ret = xmlXPathNAN;
5876 break;
5877 }
5878 return(ret);
5879}
5880
5881/**
5882 * xmlXPathConvertNumber:
5883 * @val: an XPath object
5884 *
5885 * Converts an existing object to its number() equivalent
5886 *
5887 * Returns the new object, the old one is freed (or the operation
5888 * is done directly on @val)
5889 */
5890xmlXPathObjectPtr
5891xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5892 xmlXPathObjectPtr ret;
5893
5894 if (val == NULL)
5895 return(xmlXPathNewFloat(0.0));
5896 if (val->type == XPATH_NUMBER)
5897 return(val);
5898 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5899 xmlXPathFreeObject(val);
5900 return(ret);
5901}
5902
5903/**
5904 * xmlXPathCastNumberToBoolean:
5905 * @val: a number
5906 *
5907 * Converts a number to its boolean value
5908 *
5909 * Returns the boolean value
5910 */
5911int
5912xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00005913 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005914 return(0);
5915 return(1);
5916}
5917
5918/**
5919 * xmlXPathCastStringToBoolean:
5920 * @val: a string
5921 *
5922 * Converts a string to its boolean value
5923 *
5924 * Returns the boolean value
5925 */
5926int
5927xmlXPathCastStringToBoolean (const xmlChar *val) {
5928 if ((val == NULL) || (xmlStrlen(val) == 0))
5929 return(0);
5930 return(1);
5931}
5932
5933/**
5934 * xmlXPathCastNodeSetToBoolean:
5935 * @ns: a node-set
5936 *
5937 * Converts a node-set to its boolean value
5938 *
5939 * Returns the boolean value
5940 */
5941int
5942xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5943 if ((ns == NULL) || (ns->nodeNr == 0))
5944 return(0);
5945 return(1);
5946}
5947
5948/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005949 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005950 * @val: an XPath object
5951 *
5952 * Converts an XPath object to its boolean value
5953 *
5954 * Returns the boolean value
5955 */
5956int
5957xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5958 int ret = 0;
5959
5960 if (val == NULL)
5961 return(0);
5962 switch (val->type) {
5963 case XPATH_UNDEFINED:
5964#ifdef DEBUG_EXPR
5965 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
5966#endif
5967 ret = 0;
5968 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005969 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005970 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005971 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5972 break;
5973 case XPATH_STRING:
5974 ret = xmlXPathCastStringToBoolean(val->stringval);
5975 break;
5976 case XPATH_NUMBER:
5977 ret = xmlXPathCastNumberToBoolean(val->floatval);
5978 break;
5979 case XPATH_BOOLEAN:
5980 ret = val->boolval;
5981 break;
5982 case XPATH_USERS:
5983 case XPATH_POINT:
5984 case XPATH_RANGE:
5985 case XPATH_LOCATIONSET:
5986 TODO;
5987 ret = 0;
5988 break;
5989 }
5990 return(ret);
5991}
5992
5993
5994/**
5995 * xmlXPathConvertBoolean:
5996 * @val: an XPath object
5997 *
5998 * Converts an existing object to its boolean() equivalent
5999 *
6000 * Returns the new object, the old one is freed (or the operation
6001 * is done directly on @val)
6002 */
6003xmlXPathObjectPtr
6004xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6005 xmlXPathObjectPtr ret;
6006
6007 if (val == NULL)
6008 return(xmlXPathNewBoolean(0));
6009 if (val->type == XPATH_BOOLEAN)
6010 return(val);
6011 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6012 xmlXPathFreeObject(val);
6013 return(ret);
6014}
6015
Owen Taylor3473f882001-02-23 17:55:21 +00006016/************************************************************************
6017 * *
6018 * Routines to handle XPath contexts *
6019 * *
6020 ************************************************************************/
6021
6022/**
6023 * xmlXPathNewContext:
6024 * @doc: the XML document
6025 *
6026 * Create a new xmlXPathContext
6027 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00006028 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00006029 */
6030xmlXPathContextPtr
6031xmlXPathNewContext(xmlDocPtr doc) {
6032 xmlXPathContextPtr ret;
6033
6034 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6035 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006036 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006037 return(NULL);
6038 }
6039 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6040 ret->doc = doc;
6041 ret->node = NULL;
6042
6043 ret->varHash = NULL;
6044
6045 ret->nb_types = 0;
6046 ret->max_types = 0;
6047 ret->types = NULL;
6048
6049 ret->funcHash = xmlHashCreate(0);
6050
6051 ret->nb_axis = 0;
6052 ret->max_axis = 0;
6053 ret->axis = NULL;
6054
6055 ret->nsHash = NULL;
6056 ret->user = NULL;
6057
6058 ret->contextSize = -1;
6059 ret->proximityPosition = -1;
6060
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006061#ifdef XP_DEFAULT_CACHE_ON
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006062 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006063 xmlXPathFreeContext(ret);
6064 return(NULL);
6065 }
6066#endif
6067
Daniel Veillard45490ae2008-07-29 09:13:19 +00006068 xmlXPathRegisterAllFunctions(ret);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006069
Owen Taylor3473f882001-02-23 17:55:21 +00006070 return(ret);
6071}
6072
6073/**
6074 * xmlXPathFreeContext:
6075 * @ctxt: the context to free
6076 *
6077 * Free up an xmlXPathContext
6078 */
6079void
6080xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006081 if (ctxt == NULL) return;
6082
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006083 if (ctxt->cache != NULL)
6084 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
Owen Taylor3473f882001-02-23 17:55:21 +00006085 xmlXPathRegisteredNsCleanup(ctxt);
6086 xmlXPathRegisteredFuncsCleanup(ctxt);
6087 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006088 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00006089 xmlFree(ctxt);
6090}
6091
6092/************************************************************************
6093 * *
6094 * Routines to handle XPath parser contexts *
6095 * *
6096 ************************************************************************/
6097
6098#define CHECK_CTXT(ctxt) \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006099 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00006100 __xmlRaiseError(NULL, NULL, NULL, \
6101 NULL, NULL, XML_FROM_XPATH, \
6102 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6103 __FILE__, __LINE__, \
6104 NULL, NULL, NULL, 0, 0, \
6105 "NULL context pointer\n"); \
6106 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00006107 } \
6108
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006109#define CHECK_CTXT_NEG(ctxt) \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006110 if (ctxt == NULL) { \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006111 __xmlRaiseError(NULL, NULL, NULL, \
6112 NULL, NULL, XML_FROM_XPATH, \
6113 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6114 __FILE__, __LINE__, \
6115 NULL, NULL, NULL, 0, 0, \
6116 "NULL context pointer\n"); \
6117 return(-1); \
6118 } \
6119
Owen Taylor3473f882001-02-23 17:55:21 +00006120
6121#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00006122 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006123 (ctxt->doc->children == NULL)) { \
Daniel Veillard57b25162004-11-06 14:50:18 +00006124 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00006125 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00006126 }
Owen Taylor3473f882001-02-23 17:55:21 +00006127
6128
6129/**
6130 * xmlXPathNewParserContext:
6131 * @str: the XPath expression
6132 * @ctxt: the XPath context
6133 *
6134 * Create a new xmlXPathParserContext
6135 *
6136 * Returns the xmlXPathParserContext just allocated.
6137 */
6138xmlXPathParserContextPtr
6139xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6140 xmlXPathParserContextPtr ret;
6141
6142 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6143 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006144 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006145 return(NULL);
6146 }
6147 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6148 ret->cur = ret->base = str;
6149 ret->context = ctxt;
6150
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006151 ret->comp = xmlXPathNewCompExpr();
6152 if (ret->comp == NULL) {
6153 xmlFree(ret->valueTab);
6154 xmlFree(ret);
6155 return(NULL);
6156 }
Daniel Veillard4773df22004-01-23 13:15:13 +00006157 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6158 ret->comp->dict = ctxt->dict;
6159 xmlDictReference(ret->comp->dict);
6160 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006161
6162 return(ret);
6163}
6164
6165/**
6166 * xmlXPathCompParserContext:
6167 * @comp: the XPath compiled expression
6168 * @ctxt: the XPath context
6169 *
6170 * Create a new xmlXPathParserContext when processing a compiled expression
6171 *
6172 * Returns the xmlXPathParserContext just allocated.
6173 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006174static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006175xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6176 xmlXPathParserContextPtr ret;
6177
6178 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6179 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006180 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006181 return(NULL);
6182 }
6183 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6184
Owen Taylor3473f882001-02-23 17:55:21 +00006185 /* Allocate the value stack */
Daniel Veillard45490ae2008-07-29 09:13:19 +00006186 ret->valueTab = (xmlXPathObjectPtr *)
Owen Taylor3473f882001-02-23 17:55:21 +00006187 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006188 if (ret->valueTab == NULL) {
6189 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006190 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006191 return(NULL);
6192 }
Owen Taylor3473f882001-02-23 17:55:21 +00006193 ret->valueNr = 0;
6194 ret->valueMax = 10;
6195 ret->value = NULL;
Daniel Veillardf5048b32011-08-18 17:10:13 +08006196 ret->valueFrame = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006197
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006198 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006199 ret->comp = comp;
6200
Owen Taylor3473f882001-02-23 17:55:21 +00006201 return(ret);
6202}
6203
6204/**
6205 * xmlXPathFreeParserContext:
6206 * @ctxt: the context to free
6207 *
6208 * Free up an xmlXPathParserContext
6209 */
6210void
6211xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6212 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006213 xmlFree(ctxt->valueTab);
6214 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00006215 if (ctxt->comp != NULL) {
6216#ifdef XPATH_STREAMING
6217 if (ctxt->comp->stream != NULL) {
6218 xmlFreePatternList(ctxt->comp->stream);
6219 ctxt->comp->stream = NULL;
6220 }
6221#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006222 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard56de87e2005-02-16 00:22:29 +00006223 }
Owen Taylor3473f882001-02-23 17:55:21 +00006224 xmlFree(ctxt);
6225}
6226
6227/************************************************************************
6228 * *
6229 * The implicit core function library *
6230 * *
6231 ************************************************************************/
6232
Owen Taylor3473f882001-02-23 17:55:21 +00006233/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006234 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00006235 * @node: a node pointer
6236 *
6237 * Function computing the beginning of the string value of the node,
6238 * used to speed up comparisons
6239 *
6240 * Returns an int usable as a hash
6241 */
6242static unsigned int
6243xmlXPathNodeValHash(xmlNodePtr node) {
6244 int len = 2;
6245 const xmlChar * string = NULL;
6246 xmlNodePtr tmp = NULL;
6247 unsigned int ret = 0;
6248
6249 if (node == NULL)
6250 return(0);
6251
Daniel Veillard9adc0462003-03-24 18:39:54 +00006252 if (node->type == XML_DOCUMENT_NODE) {
6253 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6254 if (tmp == NULL)
6255 node = node->children;
6256 else
6257 node = tmp;
6258
6259 if (node == NULL)
6260 return(0);
6261 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006262
6263 switch (node->type) {
6264 case XML_COMMENT_NODE:
6265 case XML_PI_NODE:
6266 case XML_CDATA_SECTION_NODE:
6267 case XML_TEXT_NODE:
6268 string = node->content;
6269 if (string == NULL)
6270 return(0);
6271 if (string[0] == 0)
6272 return(0);
6273 return(((unsigned int) string[0]) +
6274 (((unsigned int) string[1]) << 8));
6275 case XML_NAMESPACE_DECL:
6276 string = ((xmlNsPtr)node)->href;
6277 if (string == NULL)
6278 return(0);
6279 if (string[0] == 0)
6280 return(0);
6281 return(((unsigned int) string[0]) +
6282 (((unsigned int) string[1]) << 8));
6283 case XML_ATTRIBUTE_NODE:
6284 tmp = ((xmlAttrPtr) node)->children;
6285 break;
6286 case XML_ELEMENT_NODE:
6287 tmp = node->children;
6288 break;
6289 default:
6290 return(0);
6291 }
6292 while (tmp != NULL) {
6293 switch (tmp->type) {
6294 case XML_COMMENT_NODE:
6295 case XML_PI_NODE:
6296 case XML_CDATA_SECTION_NODE:
6297 case XML_TEXT_NODE:
6298 string = tmp->content;
6299 break;
6300 case XML_NAMESPACE_DECL:
6301 string = ((xmlNsPtr)tmp)->href;
6302 break;
6303 default:
6304 break;
6305 }
6306 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006307 if (len == 1) {
6308 return(ret + (((unsigned int) string[0]) << 8));
6309 }
6310 if (string[1] == 0) {
6311 len = 1;
6312 ret = (unsigned int) string[0];
6313 } else {
6314 return(((unsigned int) string[0]) +
6315 (((unsigned int) string[1]) << 8));
6316 }
6317 }
6318 /*
6319 * Skip to next node
6320 */
6321 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6322 if (tmp->children->type != XML_ENTITY_DECL) {
6323 tmp = tmp->children;
6324 continue;
6325 }
6326 }
6327 if (tmp == node)
6328 break;
6329
6330 if (tmp->next != NULL) {
6331 tmp = tmp->next;
6332 continue;
6333 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00006334
Daniel Veillardf06307e2001-07-03 10:35:50 +00006335 do {
6336 tmp = tmp->parent;
6337 if (tmp == NULL)
6338 break;
6339 if (tmp == node) {
6340 tmp = NULL;
6341 break;
6342 }
6343 if (tmp->next != NULL) {
6344 tmp = tmp->next;
6345 break;
6346 }
6347 } while (tmp != NULL);
6348 }
6349 return(ret);
6350}
6351
6352/**
6353 * xmlXPathStringHash:
6354 * @string: a string
6355 *
6356 * Function computing the beginning of the string value of the node,
6357 * used to speed up comparisons
6358 *
6359 * Returns an int usable as a hash
6360 */
6361static unsigned int
6362xmlXPathStringHash(const xmlChar * string) {
6363 if (string == NULL)
6364 return((unsigned int) 0);
6365 if (string[0] == 0)
6366 return(0);
6367 return(((unsigned int) string[0]) +
6368 (((unsigned int) string[1]) << 8));
6369}
6370
6371/**
Owen Taylor3473f882001-02-23 17:55:21 +00006372 * xmlXPathCompareNodeSetFloat:
6373 * @ctxt: the XPath Parser context
6374 * @inf: less than (1) or greater than (0)
6375 * @strict: is the comparison strict
6376 * @arg: the node set
6377 * @f: the value
6378 *
6379 * Implement the compare operation between a nodeset and a number
6380 * @ns < @val (1, 1, ...
6381 * @ns <= @val (1, 0, ...
6382 * @ns > @val (0, 1, ...
6383 * @ns >= @val (0, 0, ...
6384 *
6385 * If one object to be compared is a node-set and the other is a number,
6386 * then the comparison will be true if and only if there is a node in the
6387 * node-set such that the result of performing the comparison on the number
6388 * to be compared and on the result of converting the string-value of that
6389 * node to a number using the number function is true.
6390 *
6391 * Returns 0 or 1 depending on the results of the test.
6392 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006393static int
Owen Taylor3473f882001-02-23 17:55:21 +00006394xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6395 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6396 int i, ret = 0;
6397 xmlNodeSetPtr ns;
6398 xmlChar *str2;
6399
6400 if ((f == NULL) || (arg == NULL) ||
6401 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006402 xmlXPathReleaseObject(ctxt->context, arg);
6403 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006404 return(0);
6405 }
6406 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006407 if (ns != NULL) {
6408 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006409 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006410 if (str2 != NULL) {
6411 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006412 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006413 xmlFree(str2);
6414 xmlXPathNumberFunction(ctxt, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006415 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006416 ret = xmlXPathCompareValues(ctxt, inf, strict);
6417 if (ret)
6418 break;
6419 }
6420 }
Owen Taylor3473f882001-02-23 17:55:21 +00006421 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006422 xmlXPathReleaseObject(ctxt->context, arg);
6423 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006424 return(ret);
6425}
6426
6427/**
6428 * xmlXPathCompareNodeSetString:
6429 * @ctxt: the XPath Parser context
6430 * @inf: less than (1) or greater than (0)
6431 * @strict: is the comparison strict
6432 * @arg: the node set
6433 * @s: the value
6434 *
6435 * Implement the compare operation between a nodeset and a string
6436 * @ns < @val (1, 1, ...
6437 * @ns <= @val (1, 0, ...
6438 * @ns > @val (0, 1, ...
6439 * @ns >= @val (0, 0, ...
6440 *
6441 * If one object to be compared is a node-set and the other is a string,
6442 * then the comparison will be true if and only if there is a node in
6443 * the node-set such that the result of performing the comparison on the
6444 * string-value of the node and the other string is true.
6445 *
6446 * Returns 0 or 1 depending on the results of the test.
6447 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006448static int
Owen Taylor3473f882001-02-23 17:55:21 +00006449xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6450 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6451 int i, ret = 0;
6452 xmlNodeSetPtr ns;
6453 xmlChar *str2;
6454
6455 if ((s == NULL) || (arg == NULL) ||
6456 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006457 xmlXPathReleaseObject(ctxt->context, arg);
6458 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006459 return(0);
6460 }
6461 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006462 if (ns != NULL) {
6463 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006464 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006465 if (str2 != NULL) {
6466 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006467 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006468 xmlFree(str2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006469 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006470 ret = xmlXPathCompareValues(ctxt, inf, strict);
6471 if (ret)
6472 break;
6473 }
6474 }
Owen Taylor3473f882001-02-23 17:55:21 +00006475 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006476 xmlXPathReleaseObject(ctxt->context, arg);
6477 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006478 return(ret);
6479}
6480
6481/**
6482 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006483 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00006484 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006485 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00006486 * @arg2: the second node set object
6487 *
6488 * Implement the compare operation on nodesets:
6489 *
6490 * If both objects to be compared are node-sets, then the comparison
6491 * will be true if and only if there is a node in the first node-set
6492 * and a node in the second node-set such that the result of performing
Daniel Veillard45490ae2008-07-29 09:13:19 +00006493 * the comparison on the string-values of the two nodes is true.
Owen Taylor3473f882001-02-23 17:55:21 +00006494 * ....
6495 * When neither object to be compared is a node-set and the operator
6496 * is <=, <, >= or >, then the objects are compared by converting both
6497 * objects to numbers and comparing the numbers according to IEEE 754.
6498 * ....
6499 * The number function converts its argument to a number as follows:
6500 * - a string that consists of optional whitespace followed by an
6501 * optional minus sign followed by a Number followed by whitespace
6502 * is converted to the IEEE 754 number that is nearest (according
6503 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6504 * represented by the string; any other string is converted to NaN
6505 *
6506 * Conclusion all nodes need to be converted first to their string value
Daniel Veillard45490ae2008-07-29 09:13:19 +00006507 * and then the comparison must be done when possible
Owen Taylor3473f882001-02-23 17:55:21 +00006508 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006509static int
6510xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00006511 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6512 int i, j, init = 0;
6513 double val1;
6514 double *values2;
6515 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006516 xmlNodeSetPtr ns1;
6517 xmlNodeSetPtr ns2;
6518
6519 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006520 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6521 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006522 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006523 }
Owen Taylor3473f882001-02-23 17:55:21 +00006524 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006525 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6526 xmlXPathFreeObject(arg1);
6527 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006528 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006529 }
Owen Taylor3473f882001-02-23 17:55:21 +00006530
6531 ns1 = arg1->nodesetval;
6532 ns2 = arg2->nodesetval;
6533
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006534 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006535 xmlXPathFreeObject(arg1);
6536 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006537 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006538 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006539 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006540 xmlXPathFreeObject(arg1);
6541 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006542 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006543 }
Owen Taylor3473f882001-02-23 17:55:21 +00006544
6545 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6546 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006547 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00006548 xmlXPathFreeObject(arg1);
6549 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006550 return(0);
6551 }
6552 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006553 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00006554 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00006555 continue;
6556 for (j = 0;j < ns2->nodeNr;j++) {
6557 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006558 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00006559 }
Daniel Veillardcda96922001-08-21 10:56:31 +00006560 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00006561 continue;
Daniel Veillard45490ae2008-07-29 09:13:19 +00006562 if (inf && strict)
Owen Taylor3473f882001-02-23 17:55:21 +00006563 ret = (val1 < values2[j]);
6564 else if (inf && !strict)
6565 ret = (val1 <= values2[j]);
6566 else if (!inf && strict)
6567 ret = (val1 > values2[j]);
6568 else if (!inf && !strict)
6569 ret = (val1 >= values2[j]);
6570 if (ret)
6571 break;
6572 }
6573 if (ret)
6574 break;
6575 init = 1;
6576 }
6577 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006578 xmlXPathFreeObject(arg1);
6579 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006580 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006581}
6582
6583/**
6584 * xmlXPathCompareNodeSetValue:
6585 * @ctxt: the XPath Parser context
6586 * @inf: less than (1) or greater than (0)
6587 * @strict: is the comparison strict
6588 * @arg: the node set
6589 * @val: the value
6590 *
6591 * Implement the compare operation between a nodeset and a value
6592 * @ns < @val (1, 1, ...
6593 * @ns <= @val (1, 0, ...
6594 * @ns > @val (0, 1, ...
6595 * @ns >= @val (0, 0, ...
6596 *
6597 * If one object to be compared is a node-set and the other is a boolean,
6598 * then the comparison will be true if and only if the result of performing
6599 * the comparison on the boolean and on the result of converting
6600 * the node-set to a boolean using the boolean function is true.
6601 *
6602 * Returns 0 or 1 depending on the results of the test.
6603 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006604static int
Owen Taylor3473f882001-02-23 17:55:21 +00006605xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6606 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6607 if ((val == NULL) || (arg == NULL) ||
6608 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6609 return(0);
6610
6611 switch(val->type) {
6612 case XPATH_NUMBER:
6613 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6614 case XPATH_NODESET:
6615 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006616 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00006617 case XPATH_STRING:
6618 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6619 case XPATH_BOOLEAN:
6620 valuePush(ctxt, arg);
6621 xmlXPathBooleanFunction(ctxt, 1);
6622 valuePush(ctxt, val);
6623 return(xmlXPathCompareValues(ctxt, inf, strict));
6624 default:
6625 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00006626 }
6627 return(0);
6628}
6629
6630/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006631 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00006632 * @arg: the nodeset object argument
6633 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00006634 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006635 *
6636 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6637 * If one object to be compared is a node-set and the other is a string,
6638 * then the comparison will be true if and only if there is a node in
6639 * the node-set such that the result of performing the comparison on the
6640 * string-value of the node and the other string is true.
6641 *
6642 * Returns 0 or 1 depending on the results of the test.
6643 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006644static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006645xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006646{
Owen Taylor3473f882001-02-23 17:55:21 +00006647 int i;
6648 xmlNodeSetPtr ns;
6649 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006650 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00006651
6652 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00006653 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6654 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006655 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00006656 /*
6657 * A NULL nodeset compared with a string is always false
6658 * (since there is no node equal, and no node not equal)
6659 */
6660 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00006661 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00006662 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006663 for (i = 0; i < ns->nodeNr; i++) {
6664 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6665 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6666 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6667 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006668 if (neq)
6669 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006670 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00006671 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6672 if (neq)
6673 continue;
6674 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006675 } else if (neq) {
6676 if (str2 != NULL)
6677 xmlFree(str2);
6678 return (1);
6679 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006680 if (str2 != NULL)
6681 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006682 } else if (neq)
6683 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00006684 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006685 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006686}
6687
6688/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006689 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00006690 * @arg: the nodeset object argument
6691 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00006692 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006693 *
6694 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6695 * If one object to be compared is a node-set and the other is a number,
6696 * then the comparison will be true if and only if there is a node in
6697 * the node-set such that the result of performing the comparison on the
6698 * number to be compared and on the result of converting the string-value
6699 * of that node to a number using the number function is true.
6700 *
6701 * Returns 0 or 1 depending on the results of the test.
6702 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006703static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006704xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6705 xmlXPathObjectPtr arg, double f, int neq) {
6706 int i, ret=0;
6707 xmlNodeSetPtr ns;
6708 xmlChar *str2;
6709 xmlXPathObjectPtr val;
6710 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00006711
6712 if ((arg == NULL) ||
6713 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6714 return(0);
6715
William M. Brack0c022ad2002-07-12 00:56:01 +00006716 ns = arg->nodesetval;
6717 if (ns != NULL) {
6718 for (i=0;i<ns->nodeNr;i++) {
6719 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6720 if (str2 != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006721 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
William M. Brack0c022ad2002-07-12 00:56:01 +00006722 xmlFree(str2);
6723 xmlXPathNumberFunction(ctxt, 1);
6724 val = valuePop(ctxt);
6725 v = val->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006726 xmlXPathReleaseObject(ctxt->context, val);
William M. Brack0c022ad2002-07-12 00:56:01 +00006727 if (!xmlXPathIsNaN(v)) {
6728 if ((!neq) && (v==f)) {
6729 ret = 1;
6730 break;
6731 } else if ((neq) && (v!=f)) {
6732 ret = 1;
6733 break;
6734 }
William M. Brack32f0f712005-07-14 07:00:33 +00006735 } else { /* NaN is unequal to any value */
6736 if (neq)
6737 ret = 1;
William M. Brack0c022ad2002-07-12 00:56:01 +00006738 }
6739 }
6740 }
6741 }
6742
6743 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006744}
6745
6746
6747/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006748 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00006749 * @arg1: first nodeset object argument
6750 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00006751 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006752 *
William M. Brack0c022ad2002-07-12 00:56:01 +00006753 * Implement the equal / not equal operation on XPath nodesets:
6754 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00006755 * If both objects to be compared are node-sets, then the comparison
6756 * will be true if and only if there is a node in the first node-set and
6757 * a node in the second node-set such that the result of performing the
6758 * comparison on the string-values of the two nodes is true.
6759 *
6760 * (needless to say, this is a costly operation)
6761 *
6762 * Returns 0 or 1 depending on the results of the test.
6763 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006764static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006765xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00006766 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006767 unsigned int *hashs1;
6768 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00006769 xmlChar **values1;
6770 xmlChar **values2;
6771 int ret = 0;
6772 xmlNodeSetPtr ns1;
6773 xmlNodeSetPtr ns2;
6774
6775 if ((arg1 == NULL) ||
6776 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6777 return(0);
6778 if ((arg2 == NULL) ||
6779 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6780 return(0);
6781
6782 ns1 = arg1->nodesetval;
6783 ns2 = arg2->nodesetval;
6784
Daniel Veillard911f49a2001-04-07 15:39:35 +00006785 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006786 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006787 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006788 return(0);
6789
6790 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00006791 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00006792 */
William M. Brack0c022ad2002-07-12 00:56:01 +00006793 if (neq == 0)
6794 for (i = 0;i < ns1->nodeNr;i++)
6795 for (j = 0;j < ns2->nodeNr;j++)
6796 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6797 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006798
6799 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006800 if (values1 == NULL) {
6801 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006802 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006803 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006804 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6805 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006806 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006807 xmlFree(values1);
6808 return(0);
6809 }
Owen Taylor3473f882001-02-23 17:55:21 +00006810 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6811 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6812 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006813 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006814 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00006815 xmlFree(values1);
6816 return(0);
6817 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006818 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6819 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006820 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006821 xmlFree(hashs1);
6822 xmlFree(values1);
6823 xmlFree(values2);
6824 return(0);
6825 }
Owen Taylor3473f882001-02-23 17:55:21 +00006826 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6827 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006828 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006829 for (j = 0;j < ns2->nodeNr;j++) {
6830 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006831 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006832 if (hashs1[i] != hashs2[j]) {
6833 if (neq) {
6834 ret = 1;
6835 break;
6836 }
6837 }
6838 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006839 if (values1[i] == NULL)
6840 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6841 if (values2[j] == NULL)
6842 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006843 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006844 if (ret)
6845 break;
6846 }
Owen Taylor3473f882001-02-23 17:55:21 +00006847 }
6848 if (ret)
6849 break;
6850 }
6851 for (i = 0;i < ns1->nodeNr;i++)
6852 if (values1[i] != NULL)
6853 xmlFree(values1[i]);
6854 for (j = 0;j < ns2->nodeNr;j++)
6855 if (values2[j] != NULL)
6856 xmlFree(values2[j]);
6857 xmlFree(values1);
6858 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006859 xmlFree(hashs1);
6860 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00006861 return(ret);
6862}
6863
William M. Brack0c022ad2002-07-12 00:56:01 +00006864static int
6865xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6866 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00006867 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00006868 /*
6869 *At this point we are assured neither arg1 nor arg2
6870 *is a nodeset, so we can just pick the appropriate routine.
6871 */
Owen Taylor3473f882001-02-23 17:55:21 +00006872 switch (arg1->type) {
6873 case XPATH_UNDEFINED:
6874#ifdef DEBUG_EXPR
6875 xmlGenericError(xmlGenericErrorContext,
6876 "Equal: undefined\n");
6877#endif
6878 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006879 case XPATH_BOOLEAN:
6880 switch (arg2->type) {
6881 case XPATH_UNDEFINED:
6882#ifdef DEBUG_EXPR
6883 xmlGenericError(xmlGenericErrorContext,
6884 "Equal: undefined\n");
6885#endif
6886 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006887 case XPATH_BOOLEAN:
6888#ifdef DEBUG_EXPR
6889 xmlGenericError(xmlGenericErrorContext,
6890 "Equal: %d boolean %d \n",
6891 arg1->boolval, arg2->boolval);
6892#endif
6893 ret = (arg1->boolval == arg2->boolval);
6894 break;
6895 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00006896 ret = (arg1->boolval ==
6897 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006898 break;
6899 case XPATH_STRING:
6900 if ((arg2->stringval == NULL) ||
6901 (arg2->stringval[0] == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00006902 else
Owen Taylor3473f882001-02-23 17:55:21 +00006903 ret = 1;
6904 ret = (arg1->boolval == ret);
6905 break;
6906 case XPATH_USERS:
6907 case XPATH_POINT:
6908 case XPATH_RANGE:
6909 case XPATH_LOCATIONSET:
6910 TODO
6911 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006912 case XPATH_NODESET:
6913 case XPATH_XSLT_TREE:
6914 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006915 }
6916 break;
6917 case XPATH_NUMBER:
6918 switch (arg2->type) {
6919 case XPATH_UNDEFINED:
6920#ifdef DEBUG_EXPR
6921 xmlGenericError(xmlGenericErrorContext,
6922 "Equal: undefined\n");
6923#endif
6924 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006925 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00006926 ret = (arg2->boolval==
6927 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006928 break;
6929 case XPATH_STRING:
6930 valuePush(ctxt, arg2);
6931 xmlXPathNumberFunction(ctxt, 1);
6932 arg2 = valuePop(ctxt);
6933 /* no break on purpose */
6934 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006935 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00006936 if (xmlXPathIsNaN(arg1->floatval) ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00006937 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00006938 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006939 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6940 if (xmlXPathIsInf(arg2->floatval) == 1)
6941 ret = 1;
6942 else
6943 ret = 0;
6944 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6945 if (xmlXPathIsInf(arg2->floatval) == -1)
6946 ret = 1;
6947 else
6948 ret = 0;
6949 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6950 if (xmlXPathIsInf(arg1->floatval) == 1)
6951 ret = 1;
6952 else
6953 ret = 0;
6954 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6955 if (xmlXPathIsInf(arg1->floatval) == -1)
6956 ret = 1;
6957 else
6958 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00006959 } else {
6960 ret = (arg1->floatval == arg2->floatval);
6961 }
Owen Taylor3473f882001-02-23 17:55:21 +00006962 break;
6963 case XPATH_USERS:
6964 case XPATH_POINT:
6965 case XPATH_RANGE:
6966 case XPATH_LOCATIONSET:
6967 TODO
6968 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006969 case XPATH_NODESET:
6970 case XPATH_XSLT_TREE:
6971 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006972 }
6973 break;
6974 case XPATH_STRING:
6975 switch (arg2->type) {
6976 case XPATH_UNDEFINED:
6977#ifdef DEBUG_EXPR
6978 xmlGenericError(xmlGenericErrorContext,
6979 "Equal: undefined\n");
6980#endif
6981 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006982 case XPATH_BOOLEAN:
6983 if ((arg1->stringval == NULL) ||
6984 (arg1->stringval[0] == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00006985 else
Owen Taylor3473f882001-02-23 17:55:21 +00006986 ret = 1;
6987 ret = (arg2->boolval == ret);
6988 break;
6989 case XPATH_STRING:
6990 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6991 break;
6992 case XPATH_NUMBER:
6993 valuePush(ctxt, arg1);
6994 xmlXPathNumberFunction(ctxt, 1);
6995 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006996 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00006997 if (xmlXPathIsNaN(arg1->floatval) ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00006998 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00006999 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007000 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7001 if (xmlXPathIsInf(arg2->floatval) == 1)
7002 ret = 1;
7003 else
7004 ret = 0;
7005 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7006 if (xmlXPathIsInf(arg2->floatval) == -1)
7007 ret = 1;
7008 else
7009 ret = 0;
7010 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7011 if (xmlXPathIsInf(arg1->floatval) == 1)
7012 ret = 1;
7013 else
7014 ret = 0;
7015 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7016 if (xmlXPathIsInf(arg1->floatval) == -1)
7017 ret = 1;
7018 else
7019 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007020 } else {
7021 ret = (arg1->floatval == arg2->floatval);
7022 }
Owen Taylor3473f882001-02-23 17:55:21 +00007023 break;
7024 case XPATH_USERS:
7025 case XPATH_POINT:
7026 case XPATH_RANGE:
7027 case XPATH_LOCATIONSET:
7028 TODO
7029 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007030 case XPATH_NODESET:
7031 case XPATH_XSLT_TREE:
7032 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007033 }
7034 break;
7035 case XPATH_USERS:
7036 case XPATH_POINT:
7037 case XPATH_RANGE:
7038 case XPATH_LOCATIONSET:
7039 TODO
7040 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007041 case XPATH_NODESET:
7042 case XPATH_XSLT_TREE:
7043 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007044 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007045 xmlXPathReleaseObject(ctxt->context, arg1);
7046 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007047 return(ret);
7048}
7049
William M. Brack0c022ad2002-07-12 00:56:01 +00007050/**
7051 * xmlXPathEqualValues:
7052 * @ctxt: the XPath Parser context
7053 *
7054 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7055 *
7056 * Returns 0 or 1 depending on the results of the test.
7057 */
7058int
7059xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7060 xmlXPathObjectPtr arg1, arg2, argtmp;
7061 int ret = 0;
7062
Daniel Veillard6128c012004-11-08 17:16:15 +00007063 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007064 arg2 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007065 arg1 = valuePop(ctxt);
7066 if ((arg1 == NULL) || (arg2 == NULL)) {
7067 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007068 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007069 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007070 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007071 XP_ERROR0(XPATH_INVALID_OPERAND);
7072 }
7073
7074 if (arg1 == arg2) {
7075#ifdef DEBUG_EXPR
7076 xmlGenericError(xmlGenericErrorContext,
7077 "Equal: by pointer\n");
7078#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00007079 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007080 return(1);
7081 }
7082
7083 /*
7084 *If either argument is a nodeset, it's a 'special case'
7085 */
7086 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7087 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7088 /*
7089 *Hack it to assure arg1 is the nodeset
7090 */
7091 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7092 argtmp = arg2;
7093 arg2 = arg1;
7094 arg1 = argtmp;
7095 }
7096 switch (arg2->type) {
7097 case XPATH_UNDEFINED:
7098#ifdef DEBUG_EXPR
7099 xmlGenericError(xmlGenericErrorContext,
7100 "Equal: undefined\n");
7101#endif
7102 break;
7103 case XPATH_NODESET:
7104 case XPATH_XSLT_TREE:
7105 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7106 break;
7107 case XPATH_BOOLEAN:
7108 if ((arg1->nodesetval == NULL) ||
7109 (arg1->nodesetval->nodeNr == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007110 else
William M. Brack0c022ad2002-07-12 00:56:01 +00007111 ret = 1;
7112 ret = (ret == arg2->boolval);
7113 break;
7114 case XPATH_NUMBER:
7115 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7116 break;
7117 case XPATH_STRING:
7118 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7119 break;
7120 case XPATH_USERS:
7121 case XPATH_POINT:
7122 case XPATH_RANGE:
7123 case XPATH_LOCATIONSET:
7124 TODO
7125 break;
7126 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007127 xmlXPathReleaseObject(ctxt->context, arg1);
7128 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007129 return(ret);
7130 }
7131
7132 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7133}
7134
7135/**
7136 * xmlXPathNotEqualValues:
7137 * @ctxt: the XPath Parser context
7138 *
7139 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7140 *
7141 * Returns 0 or 1 depending on the results of the test.
7142 */
7143int
7144xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7145 xmlXPathObjectPtr arg1, arg2, argtmp;
7146 int ret = 0;
7147
Daniel Veillard6128c012004-11-08 17:16:15 +00007148 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007149 arg2 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007150 arg1 = valuePop(ctxt);
7151 if ((arg1 == NULL) || (arg2 == NULL)) {
7152 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007153 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007154 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007155 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007156 XP_ERROR0(XPATH_INVALID_OPERAND);
7157 }
7158
7159 if (arg1 == arg2) {
7160#ifdef DEBUG_EXPR
7161 xmlGenericError(xmlGenericErrorContext,
7162 "NotEqual: by pointer\n");
7163#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007164 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007165 return(0);
7166 }
7167
7168 /*
7169 *If either argument is a nodeset, it's a 'special case'
7170 */
7171 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7172 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7173 /*
7174 *Hack it to assure arg1 is the nodeset
7175 */
7176 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7177 argtmp = arg2;
7178 arg2 = arg1;
7179 arg1 = argtmp;
7180 }
7181 switch (arg2->type) {
7182 case XPATH_UNDEFINED:
7183#ifdef DEBUG_EXPR
7184 xmlGenericError(xmlGenericErrorContext,
7185 "NotEqual: undefined\n");
7186#endif
7187 break;
7188 case XPATH_NODESET:
7189 case XPATH_XSLT_TREE:
7190 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7191 break;
7192 case XPATH_BOOLEAN:
7193 if ((arg1->nodesetval == NULL) ||
7194 (arg1->nodesetval->nodeNr == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007195 else
William M. Brack0c022ad2002-07-12 00:56:01 +00007196 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00007197 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00007198 break;
7199 case XPATH_NUMBER:
7200 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7201 break;
7202 case XPATH_STRING:
7203 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7204 break;
7205 case XPATH_USERS:
7206 case XPATH_POINT:
7207 case XPATH_RANGE:
7208 case XPATH_LOCATIONSET:
7209 TODO
7210 break;
7211 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007212 xmlXPathReleaseObject(ctxt->context, arg1);
7213 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007214 return(ret);
7215 }
7216
7217 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7218}
Owen Taylor3473f882001-02-23 17:55:21 +00007219
7220/**
7221 * xmlXPathCompareValues:
7222 * @ctxt: the XPath Parser context
7223 * @inf: less than (1) or greater than (0)
7224 * @strict: is the comparison strict
7225 *
Daniel Veillard45490ae2008-07-29 09:13:19 +00007226 * Implement the compare operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007227 * @arg1 < @arg2 (1, 1, ...
7228 * @arg1 <= @arg2 (1, 0, ...
7229 * @arg1 > @arg2 (0, 1, ...
7230 * @arg1 >= @arg2 (0, 0, ...
7231 *
7232 * When neither object to be compared is a node-set and the operator is
7233 * <=, <, >=, >, then the objects are compared by converted both objects
7234 * to numbers and comparing the numbers according to IEEE 754. The <
7235 * comparison will be true if and only if the first number is less than the
7236 * second number. The <= comparison will be true if and only if the first
7237 * number is less than or equal to the second number. The > comparison
7238 * will be true if and only if the first number is greater than the second
7239 * number. The >= comparison will be true if and only if the first number
7240 * is greater than or equal to the second number.
7241 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007242 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00007243 */
7244int
7245xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007246 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007247 xmlXPathObjectPtr arg1, arg2;
7248
Daniel Veillard6128c012004-11-08 17:16:15 +00007249 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007250 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007251 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007252 if ((arg1 == NULL) || (arg2 == NULL)) {
7253 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007254 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007255 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007256 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007257 XP_ERROR0(XPATH_INVALID_OPERAND);
7258 }
7259
William M. Brack0c022ad2002-07-12 00:56:01 +00007260 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7261 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
William M. Brackd6e347e2005-04-15 01:34:41 +00007262 /*
7263 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7264 * are not freed from within this routine; they will be freed from the
7265 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7266 */
William M. Brack0c022ad2002-07-12 00:56:01 +00007267 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7268 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007269 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007270 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00007271 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007272 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7273 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007274 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007275 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7276 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00007277 }
7278 }
7279 return(ret);
7280 }
7281
7282 if (arg1->type != XPATH_NUMBER) {
7283 valuePush(ctxt, arg1);
7284 xmlXPathNumberFunction(ctxt, 1);
7285 arg1 = valuePop(ctxt);
7286 }
7287 if (arg1->type != XPATH_NUMBER) {
7288 xmlXPathFreeObject(arg1);
7289 xmlXPathFreeObject(arg2);
7290 XP_ERROR0(XPATH_INVALID_OPERAND);
7291 }
7292 if (arg2->type != XPATH_NUMBER) {
7293 valuePush(ctxt, arg2);
7294 xmlXPathNumberFunction(ctxt, 1);
7295 arg2 = valuePop(ctxt);
7296 }
7297 if (arg2->type != XPATH_NUMBER) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007298 xmlXPathReleaseObject(ctxt->context, arg1);
7299 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007300 XP_ERROR0(XPATH_INVALID_OPERAND);
7301 }
7302 /*
7303 * Add tests for infinity and nan
7304 * => feedback on 3.4 for Inf and NaN
7305 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007306 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00007307 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007308 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007309 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007310 arg1i=xmlXPathIsInf(arg1->floatval);
7311 arg2i=xmlXPathIsInf(arg2->floatval);
7312 if (inf && strict) {
7313 if ((arg1i == -1 && arg2i != -1) ||
7314 (arg2i == 1 && arg1i != 1)) {
7315 ret = 1;
7316 } else if (arg1i == 0 && arg2i == 0) {
7317 ret = (arg1->floatval < arg2->floatval);
7318 } else {
7319 ret = 0;
7320 }
7321 }
7322 else if (inf && !strict) {
7323 if (arg1i == -1 || arg2i == 1) {
7324 ret = 1;
7325 } else if (arg1i == 0 && arg2i == 0) {
7326 ret = (arg1->floatval <= arg2->floatval);
7327 } else {
7328 ret = 0;
7329 }
7330 }
7331 else if (!inf && strict) {
7332 if ((arg1i == 1 && arg2i != 1) ||
7333 (arg2i == -1 && arg1i != -1)) {
7334 ret = 1;
7335 } else if (arg1i == 0 && arg2i == 0) {
7336 ret = (arg1->floatval > arg2->floatval);
7337 } else {
7338 ret = 0;
7339 }
7340 }
7341 else if (!inf && !strict) {
7342 if (arg1i == 1 || arg2i == -1) {
7343 ret = 1;
7344 } else if (arg1i == 0 && arg2i == 0) {
7345 ret = (arg1->floatval >= arg2->floatval);
7346 } else {
7347 ret = 0;
7348 }
7349 }
Daniel Veillard21458c82002-03-27 16:12:22 +00007350 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007351 xmlXPathReleaseObject(ctxt->context, arg1);
7352 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007353 return(ret);
7354}
7355
7356/**
7357 * xmlXPathValueFlipSign:
7358 * @ctxt: the XPath Parser context
7359 *
7360 * Implement the unary - operation on an XPath object
7361 * The numeric operators convert their operands to numbers as if
7362 * by calling the number function.
7363 */
7364void
7365xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007366 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007367 CAST_TO_NUMBER;
7368 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007369 if (xmlXPathIsNaN(ctxt->value->floatval))
7370 ctxt->value->floatval=xmlXPathNAN;
7371 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7372 ctxt->value->floatval=xmlXPathNINF;
7373 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7374 ctxt->value->floatval=xmlXPathPINF;
7375 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007376 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7377 ctxt->value->floatval = xmlXPathNZERO;
7378 else
7379 ctxt->value->floatval = 0;
7380 }
7381 else
7382 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00007383}
7384
7385/**
7386 * xmlXPathAddValues:
7387 * @ctxt: the XPath Parser context
7388 *
7389 * Implement the add operation on XPath objects:
7390 * The numeric operators convert their operands to numbers as if
7391 * by calling the number function.
7392 */
7393void
7394xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7395 xmlXPathObjectPtr arg;
7396 double val;
7397
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007398 arg = valuePop(ctxt);
7399 if (arg == NULL)
7400 XP_ERROR(XPATH_INVALID_OPERAND);
7401 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007402 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007403 CAST_TO_NUMBER;
7404 CHECK_TYPE(XPATH_NUMBER);
7405 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00007406}
7407
7408/**
7409 * xmlXPathSubValues:
7410 * @ctxt: the XPath Parser context
7411 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007412 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007413 * The numeric operators convert their operands to numbers as if
7414 * by calling the number function.
7415 */
7416void
7417xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7418 xmlXPathObjectPtr arg;
7419 double val;
7420
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007421 arg = valuePop(ctxt);
7422 if (arg == NULL)
7423 XP_ERROR(XPATH_INVALID_OPERAND);
7424 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007425 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007426 CAST_TO_NUMBER;
7427 CHECK_TYPE(XPATH_NUMBER);
7428 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007429}
7430
7431/**
7432 * xmlXPathMultValues:
7433 * @ctxt: the XPath Parser context
7434 *
7435 * Implement the multiply operation on XPath objects:
7436 * The numeric operators convert their operands to numbers as if
7437 * by calling the number function.
7438 */
7439void
7440xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7441 xmlXPathObjectPtr arg;
7442 double val;
7443
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007444 arg = valuePop(ctxt);
7445 if (arg == NULL)
7446 XP_ERROR(XPATH_INVALID_OPERAND);
7447 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007448 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007449 CAST_TO_NUMBER;
7450 CHECK_TYPE(XPATH_NUMBER);
7451 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007452}
7453
7454/**
7455 * xmlXPathDivValues:
7456 * @ctxt: the XPath Parser context
7457 *
7458 * Implement the div operation on XPath objects @arg1 / @arg2:
7459 * The numeric operators convert their operands to numbers as if
7460 * by calling the number function.
7461 */
7462void
7463xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7464 xmlXPathObjectPtr arg;
7465 double val;
7466
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007467 arg = valuePop(ctxt);
7468 if (arg == NULL)
7469 XP_ERROR(XPATH_INVALID_OPERAND);
7470 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007471 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007472 CAST_TO_NUMBER;
7473 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007474 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7475 ctxt->value->floatval = xmlXPathNAN;
7476 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007477 if (ctxt->value->floatval == 0)
7478 ctxt->value->floatval = xmlXPathNAN;
7479 else if (ctxt->value->floatval > 0)
7480 ctxt->value->floatval = xmlXPathNINF;
7481 else if (ctxt->value->floatval < 0)
7482 ctxt->value->floatval = xmlXPathPINF;
7483 }
7484 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007485 if (ctxt->value->floatval == 0)
7486 ctxt->value->floatval = xmlXPathNAN;
7487 else if (ctxt->value->floatval > 0)
7488 ctxt->value->floatval = xmlXPathPINF;
7489 else if (ctxt->value->floatval < 0)
7490 ctxt->value->floatval = xmlXPathNINF;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007491 } else
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007492 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007493}
7494
7495/**
7496 * xmlXPathModValues:
7497 * @ctxt: the XPath Parser context
7498 *
7499 * Implement the mod operation on XPath objects: @arg1 / @arg2
7500 * The numeric operators convert their operands to numbers as if
7501 * by calling the number function.
7502 */
7503void
7504xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7505 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00007506 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00007507
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007508 arg = valuePop(ctxt);
7509 if (arg == NULL)
7510 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007511 arg2 = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007512 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007513 CAST_TO_NUMBER;
7514 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007515 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00007516 if (arg2 == 0)
7517 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007518 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00007519 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007520 }
Owen Taylor3473f882001-02-23 17:55:21 +00007521}
7522
7523/************************************************************************
7524 * *
7525 * The traversal functions *
7526 * *
7527 ************************************************************************/
7528
Owen Taylor3473f882001-02-23 17:55:21 +00007529/*
7530 * A traversal function enumerates nodes along an axis.
7531 * Initially it must be called with NULL, and it indicates
7532 * termination on the axis by returning NULL.
7533 */
7534typedef xmlNodePtr (*xmlXPathTraversalFunction)
7535 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7536
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007537/*
7538 * xmlXPathTraversalFunctionExt:
7539 * A traversal function enumerates nodes along an axis.
7540 * Initially it must be called with NULL, and it indicates
7541 * termination on the axis by returning NULL.
7542 * The context node of the traversal is specified via @contextNode.
7543 */
7544typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7545 (xmlNodePtr cur, xmlNodePtr contextNode);
7546
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00007547/*
7548 * xmlXPathNodeSetMergeFunction:
7549 * Used for merging node sets in xmlXPathCollectAndTest().
7550 */
7551typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7552 (xmlNodeSetPtr, xmlNodeSetPtr, int);
7553
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007554
Owen Taylor3473f882001-02-23 17:55:21 +00007555/**
7556 * xmlXPathNextSelf:
7557 * @ctxt: the XPath Parser context
7558 * @cur: the current node in the traversal
7559 *
7560 * Traversal function for the "self" direction
7561 * The self axis contains just the context node itself
7562 *
7563 * Returns the next element following that axis
7564 */
7565xmlNodePtr
7566xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007567 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007568 if (cur == NULL)
7569 return(ctxt->context->node);
7570 return(NULL);
7571}
7572
7573/**
7574 * xmlXPathNextChild:
7575 * @ctxt: the XPath Parser context
7576 * @cur: the current node in the traversal
7577 *
7578 * Traversal function for the "child" direction
7579 * The child axis contains the children of the context node in document order.
7580 *
7581 * Returns the next element following that axis
7582 */
7583xmlNodePtr
7584xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007585 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007586 if (cur == NULL) {
7587 if (ctxt->context->node == NULL) return(NULL);
7588 switch (ctxt->context->node->type) {
7589 case XML_ELEMENT_NODE:
7590 case XML_TEXT_NODE:
7591 case XML_CDATA_SECTION_NODE:
7592 case XML_ENTITY_REF_NODE:
7593 case XML_ENTITY_NODE:
7594 case XML_PI_NODE:
7595 case XML_COMMENT_NODE:
7596 case XML_NOTATION_NODE:
7597 case XML_DTD_NODE:
7598 return(ctxt->context->node->children);
7599 case XML_DOCUMENT_NODE:
7600 case XML_DOCUMENT_TYPE_NODE:
7601 case XML_DOCUMENT_FRAG_NODE:
7602 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007603#ifdef LIBXML_DOCB_ENABLED
7604 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007605#endif
7606 return(((xmlDocPtr) ctxt->context->node)->children);
7607 case XML_ELEMENT_DECL:
7608 case XML_ATTRIBUTE_DECL:
7609 case XML_ENTITY_DECL:
7610 case XML_ATTRIBUTE_NODE:
7611 case XML_NAMESPACE_DECL:
7612 case XML_XINCLUDE_START:
7613 case XML_XINCLUDE_END:
7614 return(NULL);
7615 }
7616 return(NULL);
7617 }
7618 if ((cur->type == XML_DOCUMENT_NODE) ||
7619 (cur->type == XML_HTML_DOCUMENT_NODE))
7620 return(NULL);
7621 return(cur->next);
7622}
7623
7624/**
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00007625 * xmlXPathNextChildElement:
7626 * @ctxt: the XPath Parser context
7627 * @cur: the current node in the traversal
7628 *
7629 * Traversal function for the "child" direction and nodes of type element.
7630 * The child axis contains the children of the context node in document order.
7631 *
7632 * Returns the next element following that axis
7633 */
7634static xmlNodePtr
7635xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7636 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7637 if (cur == NULL) {
7638 cur = ctxt->context->node;
7639 if (cur == NULL) return(NULL);
7640 /*
7641 * Get the first element child.
7642 */
7643 switch (cur->type) {
7644 case XML_ELEMENT_NODE:
7645 case XML_DOCUMENT_FRAG_NODE:
7646 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7647 case XML_ENTITY_NODE:
7648 cur = cur->children;
7649 if (cur != NULL) {
7650 if (cur->type == XML_ELEMENT_NODE)
7651 return(cur);
7652 do {
7653 cur = cur->next;
7654 } while ((cur != NULL) &&
7655 (cur->type != XML_ELEMENT_NODE));
7656 return(cur);
7657 }
7658 return(NULL);
7659 case XML_DOCUMENT_NODE:
7660 case XML_HTML_DOCUMENT_NODE:
7661#ifdef LIBXML_DOCB_ENABLED
7662 case XML_DOCB_DOCUMENT_NODE:
7663#endif
7664 return(xmlDocGetRootElement((xmlDocPtr) cur));
7665 default:
7666 return(NULL);
7667 }
7668 return(NULL);
7669 }
7670 /*
7671 * Get the next sibling element node.
7672 */
7673 switch (cur->type) {
7674 case XML_ELEMENT_NODE:
7675 case XML_TEXT_NODE:
7676 case XML_ENTITY_REF_NODE:
7677 case XML_ENTITY_NODE:
7678 case XML_CDATA_SECTION_NODE:
7679 case XML_PI_NODE:
7680 case XML_COMMENT_NODE:
7681 case XML_XINCLUDE_END:
7682 break;
7683 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7684 default:
7685 return(NULL);
7686 }
7687 if (cur->next != NULL) {
7688 if (cur->next->type == XML_ELEMENT_NODE)
7689 return(cur->next);
7690 cur = cur->next;
7691 do {
7692 cur = cur->next;
7693 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7694 return(cur);
7695 }
7696 return(NULL);
7697}
7698
7699/**
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007700 * xmlXPathNextDescendantOrSelfElemParent:
7701 * @ctxt: the XPath Parser context
7702 * @cur: the current node in the traversal
7703 *
7704 * Traversal function for the "descendant-or-self" axis.
7705 * Additionally it returns only nodes which can be parents of
7706 * element nodes.
7707 *
7708 *
7709 * Returns the next element following that axis
7710 */
7711static xmlNodePtr
7712xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7713 xmlNodePtr contextNode)
7714{
7715 if (cur == NULL) {
7716 if (contextNode == NULL)
7717 return(NULL);
7718 switch (contextNode->type) {
7719 case XML_ELEMENT_NODE:
7720 case XML_XINCLUDE_START:
7721 case XML_DOCUMENT_FRAG_NODE:
7722 case XML_DOCUMENT_NODE:
7723#ifdef LIBXML_DOCB_ENABLED
7724 case XML_DOCB_DOCUMENT_NODE:
7725#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00007726 case XML_HTML_DOCUMENT_NODE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007727 return(contextNode);
7728 default:
Daniel Veillard45490ae2008-07-29 09:13:19 +00007729 return(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007730 }
7731 return(NULL);
7732 } else {
7733 xmlNodePtr start = cur;
7734
7735 while (cur != NULL) {
7736 switch (cur->type) {
7737 case XML_ELEMENT_NODE:
7738 /* TODO: OK to have XInclude here? */
7739 case XML_XINCLUDE_START:
Daniel Veillard45490ae2008-07-29 09:13:19 +00007740 case XML_DOCUMENT_FRAG_NODE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007741 if (cur != start)
7742 return(cur);
7743 if (cur->children != NULL) {
7744 cur = cur->children;
7745 continue;
7746 }
7747 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007748 /* Not sure if we need those here. */
7749 case XML_DOCUMENT_NODE:
Daniel Veillard17970a72006-10-26 08:55:47 +00007750#ifdef LIBXML_DOCB_ENABLED
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007751 case XML_DOCB_DOCUMENT_NODE:
7752#endif
7753 case XML_HTML_DOCUMENT_NODE:
7754 if (cur != start)
7755 return(cur);
7756 return(xmlDocGetRootElement((xmlDocPtr) cur));
7757 default:
7758 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007759 }
7760
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007761next_sibling:
7762 if ((cur == NULL) || (cur == contextNode))
Daniel Veillard45490ae2008-07-29 09:13:19 +00007763 return(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007764 if (cur->next != NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00007765 cur = cur->next;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007766 } else {
7767 cur = cur->parent;
7768 goto next_sibling;
7769 }
7770 }
7771 }
7772 return(NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007773}
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007774
7775/**
Owen Taylor3473f882001-02-23 17:55:21 +00007776 * xmlXPathNextDescendant:
7777 * @ctxt: the XPath Parser context
7778 * @cur: the current node in the traversal
7779 *
7780 * Traversal function for the "descendant" direction
7781 * the descendant axis contains the descendants of the context node in document
7782 * order; a descendant is a child or a child of a child and so on.
7783 *
7784 * Returns the next element following that axis
7785 */
7786xmlNodePtr
7787xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007788 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007789 if (cur == NULL) {
7790 if (ctxt->context->node == NULL)
7791 return(NULL);
7792 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7793 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7794 return(NULL);
7795
7796 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7797 return(ctxt->context->doc->children);
7798 return(ctxt->context->node->children);
7799 }
7800
Daniel Veillard567e1b42001-08-01 15:53:47 +00007801 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007802 /*
7803 * Do not descend on entities declarations
7804 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00007805 if (cur->children->type != XML_ENTITY_DECL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007806 cur = cur->children;
7807 /*
7808 * Skip DTDs
7809 */
7810 if (cur->type != XML_DTD_NODE)
7811 return(cur);
7812 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00007813 }
7814
7815 if (cur == ctxt->context->node) return(NULL);
7816
Daniel Veillard68e9e742002-11-16 15:35:11 +00007817 while (cur->next != NULL) {
7818 cur = cur->next;
7819 if ((cur->type != XML_ENTITY_DECL) &&
7820 (cur->type != XML_DTD_NODE))
7821 return(cur);
7822 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00007823
Owen Taylor3473f882001-02-23 17:55:21 +00007824 do {
7825 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00007826 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00007827 if (cur == ctxt->context->node) return(NULL);
7828 if (cur->next != NULL) {
7829 cur = cur->next;
7830 return(cur);
7831 }
7832 } while (cur != NULL);
7833 return(cur);
7834}
7835
7836/**
7837 * xmlXPathNextDescendantOrSelf:
7838 * @ctxt: the XPath Parser context
7839 * @cur: the current node in the traversal
7840 *
7841 * Traversal function for the "descendant-or-self" direction
7842 * the descendant-or-self axis contains the context node and the descendants
7843 * of the context node in document order; thus the context node is the first
7844 * node on the axis, and the first child of the context node is the second node
7845 * on the axis
7846 *
7847 * Returns the next element following that axis
7848 */
7849xmlNodePtr
7850xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007851 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007852 if (cur == NULL) {
7853 if (ctxt->context->node == NULL)
7854 return(NULL);
7855 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7856 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7857 return(NULL);
7858 return(ctxt->context->node);
7859 }
7860
7861 return(xmlXPathNextDescendant(ctxt, cur));
7862}
7863
7864/**
7865 * xmlXPathNextParent:
7866 * @ctxt: the XPath Parser context
7867 * @cur: the current node in the traversal
7868 *
7869 * Traversal function for the "parent" direction
7870 * The parent axis contains the parent of the context node, if there is one.
7871 *
7872 * Returns the next element following that axis
7873 */
7874xmlNodePtr
7875xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007876 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007877 /*
7878 * the parent of an attribute or namespace node is the element
7879 * to which the attribute or namespace node is attached
7880 * Namespace handling !!!
7881 */
7882 if (cur == NULL) {
7883 if (ctxt->context->node == NULL) return(NULL);
7884 switch (ctxt->context->node->type) {
7885 case XML_ELEMENT_NODE:
7886 case XML_TEXT_NODE:
7887 case XML_CDATA_SECTION_NODE:
7888 case XML_ENTITY_REF_NODE:
7889 case XML_ENTITY_NODE:
7890 case XML_PI_NODE:
7891 case XML_COMMENT_NODE:
7892 case XML_NOTATION_NODE:
7893 case XML_DTD_NODE:
7894 case XML_ELEMENT_DECL:
7895 case XML_ATTRIBUTE_DECL:
7896 case XML_XINCLUDE_START:
7897 case XML_XINCLUDE_END:
7898 case XML_ENTITY_DECL:
7899 if (ctxt->context->node->parent == NULL)
7900 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007901 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007902 ((ctxt->context->node->parent->name[0] == ' ') ||
7903 (xmlStrEqual(ctxt->context->node->parent->name,
7904 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007905 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007906 return(ctxt->context->node->parent);
7907 case XML_ATTRIBUTE_NODE: {
7908 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7909
7910 return(att->parent);
7911 }
7912 case XML_DOCUMENT_NODE:
7913 case XML_DOCUMENT_TYPE_NODE:
7914 case XML_DOCUMENT_FRAG_NODE:
7915 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007916#ifdef LIBXML_DOCB_ENABLED
7917 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007918#endif
7919 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007920 case XML_NAMESPACE_DECL: {
7921 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007922
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007923 if ((ns->next != NULL) &&
7924 (ns->next->type != XML_NAMESPACE_DECL))
7925 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00007926 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007927 }
Owen Taylor3473f882001-02-23 17:55:21 +00007928 }
7929 }
7930 return(NULL);
7931}
7932
7933/**
7934 * xmlXPathNextAncestor:
7935 * @ctxt: the XPath Parser context
7936 * @cur: the current node in the traversal
7937 *
7938 * Traversal function for the "ancestor" direction
7939 * the ancestor axis contains the ancestors of the context node; the ancestors
7940 * of the context node consist of the parent of context node and the parent's
7941 * parent and so on; the nodes are ordered in reverse document order; thus the
7942 * parent is the first node on the axis, and the parent's parent is the second
7943 * node on the axis
7944 *
7945 * Returns the next element following that axis
7946 */
7947xmlNodePtr
7948xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007949 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007950 /*
7951 * the parent of an attribute or namespace node is the element
7952 * to which the attribute or namespace node is attached
7953 * !!!!!!!!!!!!!
7954 */
7955 if (cur == NULL) {
7956 if (ctxt->context->node == NULL) return(NULL);
7957 switch (ctxt->context->node->type) {
7958 case XML_ELEMENT_NODE:
7959 case XML_TEXT_NODE:
7960 case XML_CDATA_SECTION_NODE:
7961 case XML_ENTITY_REF_NODE:
7962 case XML_ENTITY_NODE:
7963 case XML_PI_NODE:
7964 case XML_COMMENT_NODE:
7965 case XML_DTD_NODE:
7966 case XML_ELEMENT_DECL:
7967 case XML_ATTRIBUTE_DECL:
7968 case XML_ENTITY_DECL:
7969 case XML_NOTATION_NODE:
7970 case XML_XINCLUDE_START:
7971 case XML_XINCLUDE_END:
7972 if (ctxt->context->node->parent == NULL)
7973 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007974 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007975 ((ctxt->context->node->parent->name[0] == ' ') ||
7976 (xmlStrEqual(ctxt->context->node->parent->name,
7977 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007978 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007979 return(ctxt->context->node->parent);
7980 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007981 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00007982
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007983 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00007984 }
7985 case XML_DOCUMENT_NODE:
7986 case XML_DOCUMENT_TYPE_NODE:
7987 case XML_DOCUMENT_FRAG_NODE:
7988 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007989#ifdef LIBXML_DOCB_ENABLED
7990 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007991#endif
7992 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007993 case XML_NAMESPACE_DECL: {
7994 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007995
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007996 if ((ns->next != NULL) &&
7997 (ns->next->type != XML_NAMESPACE_DECL))
7998 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00007999 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00008000 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008001 }
Owen Taylor3473f882001-02-23 17:55:21 +00008002 }
8003 return(NULL);
8004 }
8005 if (cur == ctxt->context->doc->children)
8006 return((xmlNodePtr) ctxt->context->doc);
8007 if (cur == (xmlNodePtr) ctxt->context->doc)
8008 return(NULL);
8009 switch (cur->type) {
8010 case XML_ELEMENT_NODE:
8011 case XML_TEXT_NODE:
8012 case XML_CDATA_SECTION_NODE:
8013 case XML_ENTITY_REF_NODE:
8014 case XML_ENTITY_NODE:
8015 case XML_PI_NODE:
8016 case XML_COMMENT_NODE:
8017 case XML_NOTATION_NODE:
8018 case XML_DTD_NODE:
8019 case XML_ELEMENT_DECL:
8020 case XML_ATTRIBUTE_DECL:
8021 case XML_ENTITY_DECL:
8022 case XML_XINCLUDE_START:
8023 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008024 if (cur->parent == NULL)
8025 return(NULL);
8026 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00008027 ((cur->parent->name[0] == ' ') ||
8028 (xmlStrEqual(cur->parent->name,
8029 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008030 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008031 return(cur->parent);
8032 case XML_ATTRIBUTE_NODE: {
8033 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
8034
8035 return(att->parent);
8036 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008037 case XML_NAMESPACE_DECL: {
8038 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008039
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008040 if ((ns->next != NULL) &&
8041 (ns->next->type != XML_NAMESPACE_DECL))
8042 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00008043 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008044 return(NULL);
8045 }
Owen Taylor3473f882001-02-23 17:55:21 +00008046 case XML_DOCUMENT_NODE:
8047 case XML_DOCUMENT_TYPE_NODE:
8048 case XML_DOCUMENT_FRAG_NODE:
8049 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00008050#ifdef LIBXML_DOCB_ENABLED
8051 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00008052#endif
8053 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008054 }
8055 return(NULL);
8056}
8057
8058/**
8059 * xmlXPathNextAncestorOrSelf:
8060 * @ctxt: the XPath Parser context
8061 * @cur: the current node in the traversal
8062 *
8063 * Traversal function for the "ancestor-or-self" direction
8064 * he ancestor-or-self axis contains the context node and ancestors of
8065 * the context node in reverse document order; thus the context node is
8066 * the first node on the axis, and the context node's parent the second;
8067 * parent here is defined the same as with the parent axis.
8068 *
8069 * Returns the next element following that axis
8070 */
8071xmlNodePtr
8072xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008073 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008074 if (cur == NULL)
8075 return(ctxt->context->node);
8076 return(xmlXPathNextAncestor(ctxt, cur));
8077}
8078
8079/**
8080 * xmlXPathNextFollowingSibling:
8081 * @ctxt: the XPath Parser context
8082 * @cur: the current node in the traversal
8083 *
8084 * Traversal function for the "following-sibling" direction
8085 * The following-sibling axis contains the following siblings of the context
8086 * node in document order.
8087 *
8088 * Returns the next element following that axis
8089 */
8090xmlNodePtr
8091xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008092 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008093 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8094 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8095 return(NULL);
8096 if (cur == (xmlNodePtr) ctxt->context->doc)
8097 return(NULL);
8098 if (cur == NULL)
8099 return(ctxt->context->node->next);
8100 return(cur->next);
8101}
8102
8103/**
8104 * xmlXPathNextPrecedingSibling:
8105 * @ctxt: the XPath Parser context
8106 * @cur: the current node in the traversal
8107 *
8108 * Traversal function for the "preceding-sibling" direction
8109 * The preceding-sibling axis contains the preceding siblings of the context
8110 * node in reverse document order; the first preceding sibling is first on the
8111 * axis; the sibling preceding that node is the second on the axis and so on.
8112 *
8113 * Returns the next element following that axis
8114 */
8115xmlNodePtr
8116xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008117 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008118 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8119 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8120 return(NULL);
8121 if (cur == (xmlNodePtr) ctxt->context->doc)
8122 return(NULL);
8123 if (cur == NULL)
8124 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008125 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8126 cur = cur->prev;
8127 if (cur == NULL)
8128 return(ctxt->context->node->prev);
8129 }
Owen Taylor3473f882001-02-23 17:55:21 +00008130 return(cur->prev);
8131}
8132
8133/**
8134 * xmlXPathNextFollowing:
8135 * @ctxt: the XPath Parser context
8136 * @cur: the current node in the traversal
8137 *
8138 * Traversal function for the "following" direction
8139 * The following axis contains all nodes in the same document as the context
8140 * node that are after the context node in document order, excluding any
8141 * descendants and excluding attribute nodes and namespace nodes; the nodes
8142 * are ordered in document order
8143 *
8144 * Returns the next element following that axis
8145 */
8146xmlNodePtr
8147xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008148 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008149 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
8150 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8151 return(cur->children);
8152
8153 if (cur == NULL) {
8154 cur = ctxt->context->node;
8155 if (cur->type == XML_NAMESPACE_DECL)
Daniel Veillard91d19752010-10-15 14:30:52 +02008156 return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008157 if (cur->type == XML_ATTRIBUTE_NODE)
8158 cur = cur->parent;
Daniel Veillard91d19752010-10-15 14:30:52 +02008159 }
Owen Taylor3473f882001-02-23 17:55:21 +00008160 if (cur == NULL) return(NULL) ; /* ERROR */
8161 if (cur->next != NULL) return(cur->next) ;
8162 do {
8163 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00008164 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00008165 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8166 if (cur->next != NULL) return(cur->next);
8167 } while (cur != NULL);
8168 return(cur);
8169}
8170
8171/*
8172 * xmlXPathIsAncestor:
8173 * @ancestor: the ancestor node
8174 * @node: the current node
8175 *
8176 * Check that @ancestor is a @node's ancestor
8177 *
8178 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8179 */
8180static int
8181xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8182 if ((ancestor == NULL) || (node == NULL)) return(0);
8183 /* nodes need to be in the same document */
8184 if (ancestor->doc != node->doc) return(0);
8185 /* avoid searching if ancestor or node is the root node */
8186 if (ancestor == (xmlNodePtr) node->doc) return(1);
8187 if (node == (xmlNodePtr) ancestor->doc) return(0);
8188 while (node->parent != NULL) {
8189 if (node->parent == ancestor)
8190 return(1);
8191 node = node->parent;
8192 }
8193 return(0);
8194}
8195
8196/**
8197 * xmlXPathNextPreceding:
8198 * @ctxt: the XPath Parser context
8199 * @cur: the current node in the traversal
8200 *
8201 * Traversal function for the "preceding" direction
8202 * the preceding axis contains all nodes in the same document as the context
8203 * node that are before the context node in document order, excluding any
8204 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8205 * ordered in reverse document order
8206 *
8207 * Returns the next element following that axis
8208 */
8209xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00008210xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8211{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008212 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008213 if (cur == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008214 cur = ctxt->context->node;
Daniel Veillardea90b892010-10-22 15:50:50 +02008215 if (cur->type == XML_NAMESPACE_DECL)
8216 return(NULL);
8217 if (cur->type == XML_ATTRIBUTE_NODE)
8218 return(cur->parent);
8219 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00008220 if (cur == NULL)
8221 return (NULL);
8222 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8223 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00008224 do {
8225 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008226 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8227 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008228 }
8229
8230 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008231 if (cur == NULL)
8232 return (NULL);
8233 if (cur == ctxt->context->doc->children)
8234 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008235 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00008236 return (cur);
8237}
8238
8239/**
8240 * xmlXPathNextPrecedingInternal:
8241 * @ctxt: the XPath Parser context
8242 * @cur: the current node in the traversal
8243 *
8244 * Traversal function for the "preceding" direction
8245 * the preceding axis contains all nodes in the same document as the context
8246 * node that are before the context node in document order, excluding any
8247 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8248 * ordered in reverse document order
Daniel Veillard45490ae2008-07-29 09:13:19 +00008249 * This is a faster implementation but internal only since it requires a
Daniel Veillardf06307e2001-07-03 10:35:50 +00008250 * state kept in the parser context: ctxt->ancestor.
8251 *
8252 * Returns the next element following that axis
8253 */
8254static xmlNodePtr
8255xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8256 xmlNodePtr cur)
8257{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008258 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008259 if (cur == NULL) {
8260 cur = ctxt->context->node;
8261 if (cur == NULL)
8262 return (NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008263 if (cur->type == XML_NAMESPACE_DECL)
8264 return (NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008265 ctxt->ancestor = cur->parent;
8266 }
8267 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8268 cur = cur->prev;
8269 while (cur->prev == NULL) {
8270 cur = cur->parent;
8271 if (cur == NULL)
8272 return (NULL);
8273 if (cur == ctxt->context->doc->children)
8274 return (NULL);
8275 if (cur != ctxt->ancestor)
8276 return (cur);
8277 ctxt->ancestor = cur->parent;
8278 }
8279 cur = cur->prev;
8280 while (cur->last != NULL)
8281 cur = cur->last;
8282 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008283}
8284
8285/**
8286 * xmlXPathNextNamespace:
8287 * @ctxt: the XPath Parser context
8288 * @cur: the current attribute in the traversal
8289 *
8290 * Traversal function for the "namespace" direction
8291 * the namespace axis contains the namespace nodes of the context node;
8292 * the order of nodes on this axis is implementation-defined; the axis will
8293 * be empty unless the context node is an element
8294 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008295 * We keep the XML namespace node at the end of the list.
8296 *
Owen Taylor3473f882001-02-23 17:55:21 +00008297 * Returns the next element following that axis
8298 */
8299xmlNodePtr
8300xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008301 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008302 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00008303 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008304 if (ctxt->context->tmpNsList != NULL)
8305 xmlFree(ctxt->context->tmpNsList);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008306 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00008307 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008308 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00008309 if (ctxt->context->tmpNsList != NULL) {
8310 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8311 ctxt->context->tmpNsNr++;
8312 }
8313 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008314 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008315 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00008316 if (ctxt->context->tmpNsNr > 0) {
8317 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8318 } else {
8319 if (ctxt->context->tmpNsList != NULL)
8320 xmlFree(ctxt->context->tmpNsList);
8321 ctxt->context->tmpNsList = NULL;
8322 return(NULL);
8323 }
Owen Taylor3473f882001-02-23 17:55:21 +00008324}
8325
8326/**
8327 * xmlXPathNextAttribute:
8328 * @ctxt: the XPath Parser context
8329 * @cur: the current attribute in the traversal
8330 *
8331 * Traversal function for the "attribute" direction
8332 * TODO: support DTD inherited default attributes
8333 *
8334 * Returns the next element following that axis
8335 */
8336xmlNodePtr
8337xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008338 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00008339 if (ctxt->context->node == NULL)
8340 return(NULL);
8341 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8342 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008343 if (cur == NULL) {
8344 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8345 return(NULL);
8346 return((xmlNodePtr)ctxt->context->node->properties);
8347 }
8348 return((xmlNodePtr)cur->next);
8349}
8350
8351/************************************************************************
8352 * *
8353 * NodeTest Functions *
8354 * *
8355 ************************************************************************/
8356
Owen Taylor3473f882001-02-23 17:55:21 +00008357#define IS_FUNCTION 200
8358
Owen Taylor3473f882001-02-23 17:55:21 +00008359
8360/************************************************************************
8361 * *
8362 * Implicit tree core function library *
8363 * *
8364 ************************************************************************/
8365
8366/**
8367 * xmlXPathRoot:
8368 * @ctxt: the XPath Parser context
8369 *
8370 * Initialize the context to the root of the document
8371 */
8372void
8373xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008374 if ((ctxt == NULL) || (ctxt->context == NULL))
8375 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008376 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008377 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8378 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008379}
8380
8381/************************************************************************
8382 * *
8383 * The explicit core function library *
8384 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8385 * *
8386 ************************************************************************/
8387
8388
8389/**
8390 * xmlXPathLastFunction:
8391 * @ctxt: the XPath Parser context
8392 * @nargs: the number of arguments
8393 *
8394 * Implement the last() XPath function
8395 * number last()
8396 * The last function returns the number of nodes in the context node list.
8397 */
8398void
8399xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8400 CHECK_ARITY(0);
8401 if (ctxt->context->contextSize >= 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008402 valuePush(ctxt,
8403 xmlXPathCacheNewFloat(ctxt->context,
8404 (double) ctxt->context->contextSize));
Owen Taylor3473f882001-02-23 17:55:21 +00008405#ifdef DEBUG_EXPR
8406 xmlGenericError(xmlGenericErrorContext,
8407 "last() : %d\n", ctxt->context->contextSize);
8408#endif
8409 } else {
8410 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8411 }
8412}
8413
8414/**
8415 * xmlXPathPositionFunction:
8416 * @ctxt: the XPath Parser context
8417 * @nargs: the number of arguments
8418 *
8419 * Implement the position() XPath function
8420 * number position()
8421 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008422 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00008423 * will be equal to last().
8424 */
8425void
8426xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8427 CHECK_ARITY(0);
8428 if (ctxt->context->proximityPosition >= 0) {
8429 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008430 xmlXPathCacheNewFloat(ctxt->context,
8431 (double) ctxt->context->proximityPosition));
Owen Taylor3473f882001-02-23 17:55:21 +00008432#ifdef DEBUG_EXPR
8433 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8434 ctxt->context->proximityPosition);
8435#endif
8436 } else {
8437 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8438 }
8439}
8440
8441/**
8442 * xmlXPathCountFunction:
8443 * @ctxt: the XPath Parser context
8444 * @nargs: the number of arguments
8445 *
8446 * Implement the count() XPath function
8447 * number count(node-set)
8448 */
8449void
8450xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8451 xmlXPathObjectPtr cur;
8452
8453 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008454 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008455 ((ctxt->value->type != XPATH_NODESET) &&
8456 (ctxt->value->type != XPATH_XSLT_TREE)))
8457 XP_ERROR(XPATH_INVALID_TYPE);
8458 cur = valuePop(ctxt);
8459
Daniel Veillard911f49a2001-04-07 15:39:35 +00008460 if ((cur == NULL) || (cur->nodesetval == NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008461 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00008462 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008463 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8464 (double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00008465 } else {
8466 if ((cur->nodesetval->nodeNr != 1) ||
8467 (cur->nodesetval->nodeTab == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008468 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00008469 } else {
8470 xmlNodePtr tmp;
8471 int i = 0;
8472
8473 tmp = cur->nodesetval->nodeTab[0];
8474 if (tmp != NULL) {
8475 tmp = tmp->children;
8476 while (tmp != NULL) {
8477 tmp = tmp->next;
8478 i++;
8479 }
8480 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008481 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
Daniel Veillardfe703322001-08-14 12:18:09 +00008482 }
8483 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008484 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008485}
8486
8487/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008488 * xmlXPathGetElementsByIds:
8489 * @doc: the document
8490 * @ids: a whitespace separated list of IDs
8491 *
8492 * Selects elements by their unique ID.
8493 *
8494 * Returns a node-set of selected elements.
8495 */
8496static xmlNodeSetPtr
8497xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8498 xmlNodeSetPtr ret;
8499 const xmlChar *cur = ids;
8500 xmlChar *ID;
8501 xmlAttrPtr attr;
8502 xmlNodePtr elem = NULL;
8503
Daniel Veillard7a985a12003-07-06 17:57:42 +00008504 if (ids == NULL) return(NULL);
8505
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008506 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00008507 if (ret == NULL)
8508 return(ret);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008509
William M. Brack76e95df2003-10-18 16:20:14 +00008510 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008511 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008512 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00008513 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008514
8515 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00008516 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00008517 /*
8518 * We used to check the fact that the value passed
8519 * was an NCName, but this generated much troubles for
8520 * me and Aleksey Sanin, people blatantly violated that
8521 * constaint, like Visa3D spec.
8522 * if (xmlValidateNCName(ID, 1) == 0)
8523 */
8524 attr = xmlGetID(doc, ID);
8525 if (attr != NULL) {
8526 if (attr->type == XML_ATTRIBUTE_NODE)
8527 elem = attr->parent;
8528 else if (attr->type == XML_ELEMENT_NODE)
8529 elem = (xmlNodePtr) attr;
8530 else
8531 elem = NULL;
8532 if (elem != NULL)
8533 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00008534 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008535 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00008536 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008537
William M. Brack76e95df2003-10-18 16:20:14 +00008538 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008539 ids = cur;
8540 }
8541 return(ret);
8542}
8543
8544/**
Owen Taylor3473f882001-02-23 17:55:21 +00008545 * xmlXPathIdFunction:
8546 * @ctxt: the XPath Parser context
8547 * @nargs: the number of arguments
8548 *
8549 * Implement the id() XPath function
8550 * node-set id(object)
8551 * The id function selects elements by their unique ID
8552 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8553 * then the result is the union of the result of applying id to the
8554 * string value of each of the nodes in the argument node-set. When the
8555 * argument to id is of any other type, the argument is converted to a
8556 * string as if by a call to the string function; the string is split
8557 * into a whitespace-separated list of tokens (whitespace is any sequence
8558 * of characters matching the production S); the result is a node-set
8559 * containing the elements in the same document as the context node that
8560 * have a unique ID equal to any of the tokens in the list.
8561 */
8562void
8563xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008564 xmlChar *tokens;
8565 xmlNodeSetPtr ret;
8566 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00008567
8568 CHECK_ARITY(1);
8569 obj = valuePop(ctxt);
8570 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00008571 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008572 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00008573 int i;
8574
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008575 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00008576 /*
8577 * FIXME -- in an out-of-memory condition this will behave badly.
8578 * The solution is not clear -- we already popped an item from
8579 * ctxt, so the object is in a corrupt state.
8580 */
Owen Taylor3473f882001-02-23 17:55:21 +00008581
Daniel Veillard911f49a2001-04-07 15:39:35 +00008582 if (obj->nodesetval != NULL) {
8583 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008584 tokens =
8585 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8586 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8587 ret = xmlXPathNodeSetMerge(ret, ns);
8588 xmlXPathFreeNodeSet(ns);
8589 if (tokens != NULL)
8590 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00008591 }
Owen Taylor3473f882001-02-23 17:55:21 +00008592 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008593 xmlXPathReleaseObject(ctxt->context, obj);
8594 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00008595 return;
8596 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008597 obj = xmlXPathCacheConvertString(ctxt->context, obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008598 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008599 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008600 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00008601 return;
8602}
8603
8604/**
8605 * xmlXPathLocalNameFunction:
8606 * @ctxt: the XPath Parser context
8607 * @nargs: the number of arguments
8608 *
8609 * Implement the local-name() XPath function
8610 * string local-name(node-set?)
8611 * The local-name function returns a string containing the local part
8612 * of the name of the node in the argument node-set that is first in
8613 * document order. If the node-set is empty or the first node has no
8614 * name, an empty string is returned. If the argument is omitted it
8615 * defaults to the context node.
8616 */
8617void
8618xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8619 xmlXPathObjectPtr cur;
8620
Daniel Veillarda82b1822004-11-08 16:24:57 +00008621 if (ctxt == NULL) return;
8622
Owen Taylor3473f882001-02-23 17:55:21 +00008623 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008624 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8625 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008626 nargs = 1;
8627 }
8628
8629 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008630 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008631 ((ctxt->value->type != XPATH_NODESET) &&
8632 (ctxt->value->type != XPATH_XSLT_TREE)))
8633 XP_ERROR(XPATH_INVALID_TYPE);
8634 cur = valuePop(ctxt);
8635
Daniel Veillard911f49a2001-04-07 15:39:35 +00008636 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008637 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008638 } else {
8639 int i = 0; /* Should be first in document order !!!!! */
8640 switch (cur->nodesetval->nodeTab[i]->type) {
8641 case XML_ELEMENT_NODE:
8642 case XML_ATTRIBUTE_NODE:
8643 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008644 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008645 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008646 else
8647 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008648 xmlXPathCacheNewString(ctxt->context,
8649 cur->nodesetval->nodeTab[i]->name));
Owen Taylor3473f882001-02-23 17:55:21 +00008650 break;
8651 case XML_NAMESPACE_DECL:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008652 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008653 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8654 break;
8655 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008656 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008657 }
8658 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008659 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008660}
8661
8662/**
8663 * xmlXPathNamespaceURIFunction:
8664 * @ctxt: the XPath Parser context
8665 * @nargs: the number of arguments
8666 *
8667 * Implement the namespace-uri() XPath function
8668 * string namespace-uri(node-set?)
8669 * The namespace-uri function returns a string containing the
8670 * namespace URI of the expanded name of the node in the argument
8671 * node-set that is first in document order. If the node-set is empty,
8672 * the first node has no name, or the expanded name has no namespace
8673 * URI, an empty string is returned. If the argument is omitted it
8674 * defaults to the context node.
8675 */
8676void
8677xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8678 xmlXPathObjectPtr cur;
8679
Daniel Veillarda82b1822004-11-08 16:24:57 +00008680 if (ctxt == NULL) return;
8681
Owen Taylor3473f882001-02-23 17:55:21 +00008682 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008683 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8684 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008685 nargs = 1;
8686 }
8687 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008688 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008689 ((ctxt->value->type != XPATH_NODESET) &&
8690 (ctxt->value->type != XPATH_XSLT_TREE)))
8691 XP_ERROR(XPATH_INVALID_TYPE);
8692 cur = valuePop(ctxt);
8693
Daniel Veillard911f49a2001-04-07 15:39:35 +00008694 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008695 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008696 } else {
8697 int i = 0; /* Should be first in document order !!!!! */
8698 switch (cur->nodesetval->nodeTab[i]->type) {
8699 case XML_ELEMENT_NODE:
8700 case XML_ATTRIBUTE_NODE:
8701 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008702 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008703 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008704 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008705 cur->nodesetval->nodeTab[i]->ns->href));
8706 break;
8707 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008708 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008709 }
8710 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008711 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008712}
8713
8714/**
8715 * xmlXPathNameFunction:
8716 * @ctxt: the XPath Parser context
8717 * @nargs: the number of arguments
8718 *
8719 * Implement the name() XPath function
8720 * string name(node-set?)
8721 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008722 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00008723 * order. The QName must represent the name with respect to the namespace
8724 * declarations in effect on the node whose name is being represented.
8725 * Typically, this will be the form in which the name occurred in the XML
8726 * source. This need not be the case if there are namespace declarations
8727 * in effect on the node that associate multiple prefixes with the same
8728 * namespace. However, an implementation may include information about
8729 * the original prefix in its representation of nodes; in this case, an
8730 * implementation can ensure that the returned string is always the same
8731 * as the QName used in the XML source. If the argument it omitted it
8732 * defaults to the context node.
8733 * Libxml keep the original prefix so the "real qualified name" used is
8734 * returned.
8735 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008736static void
Daniel Veillard04383752001-07-08 14:27:15 +00008737xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8738{
Owen Taylor3473f882001-02-23 17:55:21 +00008739 xmlXPathObjectPtr cur;
8740
8741 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008742 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8743 ctxt->context->node));
Daniel Veillard04383752001-07-08 14:27:15 +00008744 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008745 }
8746
8747 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00008748 if ((ctxt->value == NULL) ||
8749 ((ctxt->value->type != XPATH_NODESET) &&
8750 (ctxt->value->type != XPATH_XSLT_TREE)))
8751 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00008752 cur = valuePop(ctxt);
8753
Daniel Veillard911f49a2001-04-07 15:39:35 +00008754 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008755 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008756 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00008757 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00008758
Daniel Veillard04383752001-07-08 14:27:15 +00008759 switch (cur->nodesetval->nodeTab[i]->type) {
8760 case XML_ELEMENT_NODE:
8761 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008762 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008763 valuePush(ctxt,
8764 xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008765 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8766 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008767 valuePush(ctxt,
8768 xmlXPathCacheNewString(ctxt->context,
8769 cur->nodesetval->nodeTab[i]->name));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008770 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00008771 xmlChar *fullname;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008772
Daniel Veillardc00cda82003-04-07 10:22:39 +00008773 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8774 cur->nodesetval->nodeTab[i]->ns->prefix,
8775 NULL, 0);
8776 if (fullname == cur->nodesetval->nodeTab[i]->name)
8777 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8778 if (fullname == NULL) {
8779 XP_ERROR(XPATH_MEMORY_ERROR);
8780 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008781 valuePush(ctxt, xmlXPathCacheWrapString(
8782 ctxt->context, fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00008783 }
8784 break;
8785 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008786 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8787 cur->nodesetval->nodeTab[i]));
Daniel Veillard04383752001-07-08 14:27:15 +00008788 xmlXPathLocalNameFunction(ctxt, 1);
8789 }
Owen Taylor3473f882001-02-23 17:55:21 +00008790 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008791 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008792}
8793
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008794
8795/**
Owen Taylor3473f882001-02-23 17:55:21 +00008796 * xmlXPathStringFunction:
8797 * @ctxt: the XPath Parser context
8798 * @nargs: the number of arguments
8799 *
8800 * Implement the string() XPath function
8801 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00008802 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00008803 * - A node-set is converted to a string by returning the value of
8804 * the node in the node-set that is first in document order.
8805 * If the node-set is empty, an empty string is returned.
8806 * - A number is converted to a string as follows
Daniel Veillard45490ae2008-07-29 09:13:19 +00008807 * + NaN is converted to the string NaN
8808 * + positive zero is converted to the string 0
8809 * + negative zero is converted to the string 0
8810 * + positive infinity is converted to the string Infinity
8811 * + negative infinity is converted to the string -Infinity
Owen Taylor3473f882001-02-23 17:55:21 +00008812 * + if the number is an integer, the number is represented in
8813 * decimal form as a Number with no decimal point and no leading
8814 * zeros, preceded by a minus sign (-) if the number is negative
8815 * + otherwise, the number is represented in decimal form as a
8816 * Number including a decimal point with at least one digit
8817 * before the decimal point and at least one digit after the
8818 * decimal point, preceded by a minus sign (-) if the number
8819 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008820 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00008821 * before the decimal point; beyond the one required digit
8822 * after the decimal point there must be as many, but only as
8823 * many, more digits as are needed to uniquely distinguish the
8824 * number from all other IEEE 754 numeric values.
8825 * - The boolean false value is converted to the string false.
8826 * The boolean true value is converted to the string true.
8827 *
8828 * If the argument is omitted, it defaults to a node-set with the
8829 * context node as its only member.
8830 */
8831void
8832xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8833 xmlXPathObjectPtr cur;
8834
Daniel Veillarda82b1822004-11-08 16:24:57 +00008835 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008836 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008837 valuePush(ctxt,
8838 xmlXPathCacheWrapString(ctxt->context,
8839 xmlXPathCastNodeToString(ctxt->context->node)));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008840 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008841 }
8842
8843 CHECK_ARITY(1);
8844 cur = valuePop(ctxt);
8845 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008846 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00008847}
8848
8849/**
8850 * xmlXPathStringLengthFunction:
8851 * @ctxt: the XPath Parser context
8852 * @nargs: the number of arguments
8853 *
8854 * Implement the string-length() XPath function
8855 * number string-length(string?)
8856 * The string-length returns the number of characters in the string
8857 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8858 * the context node converted to a string, in other words the value
8859 * of the context node.
8860 */
8861void
8862xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8863 xmlXPathObjectPtr cur;
8864
8865 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008866 if ((ctxt == NULL) || (ctxt->context == NULL))
8867 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008868 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008869 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008870 } else {
8871 xmlChar *content;
8872
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008873 content = xmlXPathCastNodeToString(ctxt->context->node);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008874 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8875 xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00008876 xmlFree(content);
8877 }
8878 return;
8879 }
8880 CHECK_ARITY(1);
8881 CAST_TO_STRING;
8882 CHECK_TYPE(XPATH_STRING);
8883 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008884 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
Daniel Veillard45490ae2008-07-29 09:13:19 +00008885 xmlUTF8Strlen(cur->stringval)));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008886 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008887}
8888
8889/**
8890 * xmlXPathConcatFunction:
8891 * @ctxt: the XPath Parser context
8892 * @nargs: the number of arguments
8893 *
8894 * Implement the concat() XPath function
8895 * string concat(string, string, string*)
8896 * The concat function returns the concatenation of its arguments.
8897 */
8898void
8899xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8900 xmlXPathObjectPtr cur, newobj;
8901 xmlChar *tmp;
8902
Daniel Veillarda82b1822004-11-08 16:24:57 +00008903 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008904 if (nargs < 2) {
8905 CHECK_ARITY(2);
8906 }
8907
8908 CAST_TO_STRING;
8909 cur = valuePop(ctxt);
8910 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008911 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008912 return;
8913 }
8914 nargs--;
8915
8916 while (nargs > 0) {
8917 CAST_TO_STRING;
8918 newobj = valuePop(ctxt);
8919 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008920 xmlXPathReleaseObject(ctxt->context, newobj);
8921 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008922 XP_ERROR(XPATH_INVALID_TYPE);
8923 }
8924 tmp = xmlStrcat(newobj->stringval, cur->stringval);
8925 newobj->stringval = cur->stringval;
8926 cur->stringval = tmp;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008927 xmlXPathReleaseObject(ctxt->context, newobj);
Owen Taylor3473f882001-02-23 17:55:21 +00008928 nargs--;
8929 }
8930 valuePush(ctxt, cur);
8931}
8932
8933/**
8934 * xmlXPathContainsFunction:
8935 * @ctxt: the XPath Parser context
8936 * @nargs: the number of arguments
8937 *
8938 * Implement the contains() XPath function
8939 * boolean contains(string, string)
8940 * The contains function returns true if the first argument string
8941 * contains the second argument string, and otherwise returns false.
8942 */
8943void
8944xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8945 xmlXPathObjectPtr hay, needle;
8946
8947 CHECK_ARITY(2);
8948 CAST_TO_STRING;
8949 CHECK_TYPE(XPATH_STRING);
8950 needle = valuePop(ctxt);
8951 CAST_TO_STRING;
8952 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008953
Owen Taylor3473f882001-02-23 17:55:21 +00008954 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008955 xmlXPathReleaseObject(ctxt->context, hay);
8956 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008957 XP_ERROR(XPATH_INVALID_TYPE);
8958 }
8959 if (xmlStrstr(hay->stringval, needle->stringval))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008960 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00008961 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008962 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8963 xmlXPathReleaseObject(ctxt->context, hay);
8964 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008965}
8966
8967/**
8968 * xmlXPathStartsWithFunction:
8969 * @ctxt: the XPath Parser context
8970 * @nargs: the number of arguments
8971 *
8972 * Implement the starts-with() XPath function
8973 * boolean starts-with(string, string)
8974 * The starts-with function returns true if the first argument string
8975 * starts with the second argument string, and otherwise returns false.
8976 */
8977void
8978xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8979 xmlXPathObjectPtr hay, needle;
8980 int n;
8981
8982 CHECK_ARITY(2);
8983 CAST_TO_STRING;
8984 CHECK_TYPE(XPATH_STRING);
8985 needle = valuePop(ctxt);
8986 CAST_TO_STRING;
8987 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008988
Owen Taylor3473f882001-02-23 17:55:21 +00008989 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008990 xmlXPathReleaseObject(ctxt->context, hay);
8991 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008992 XP_ERROR(XPATH_INVALID_TYPE);
8993 }
8994 n = xmlStrlen(needle->stringval);
8995 if (xmlStrncmp(hay->stringval, needle->stringval, n))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008996 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008997 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008998 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8999 xmlXPathReleaseObject(ctxt->context, hay);
9000 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009001}
9002
9003/**
9004 * xmlXPathSubstringFunction:
9005 * @ctxt: the XPath Parser context
9006 * @nargs: the number of arguments
9007 *
9008 * Implement the substring() XPath function
9009 * string substring(string, number, number?)
9010 * The substring function returns the substring of the first argument
9011 * starting at the position specified in the second argument with
9012 * length specified in the third argument. For example,
9013 * substring("12345",2,3) returns "234". If the third argument is not
9014 * specified, it returns the substring starting at the position specified
9015 * in the second argument and continuing to the end of the string. For
9016 * example, substring("12345",2) returns "2345". More precisely, each
9017 * character in the string (see [3.6 Strings]) is considered to have a
9018 * numeric position: the position of the first character is 1, the position
9019 * of the second character is 2 and so on. The returned substring contains
9020 * those characters for which the position of the character is greater than
9021 * or equal to the second argument and, if the third argument is specified,
9022 * less than the sum of the second and third arguments; the comparisons
9023 * and addition used for the above follow the standard IEEE 754 rules. Thus:
Daniel Veillard45490ae2008-07-29 09:13:19 +00009024 * - substring("12345", 1.5, 2.6) returns "234"
9025 * - substring("12345", 0, 3) returns "12"
9026 * - substring("12345", 0 div 0, 3) returns ""
9027 * - substring("12345", 1, 0 div 0) returns ""
9028 * - substring("12345", -42, 1 div 0) returns "12345"
9029 * - substring("12345", -1 div 0, 1 div 0) returns ""
Owen Taylor3473f882001-02-23 17:55:21 +00009030 */
9031void
9032xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9033 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009034 double le=0, in;
9035 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00009036 xmlChar *ret;
9037
Owen Taylor3473f882001-02-23 17:55:21 +00009038 if (nargs < 2) {
9039 CHECK_ARITY(2);
9040 }
9041 if (nargs > 3) {
9042 CHECK_ARITY(3);
9043 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009044 /*
9045 * take care of possible last (position) argument
9046 */
Owen Taylor3473f882001-02-23 17:55:21 +00009047 if (nargs == 3) {
9048 CAST_TO_NUMBER;
9049 CHECK_TYPE(XPATH_NUMBER);
9050 len = valuePop(ctxt);
9051 le = len->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009052 xmlXPathReleaseObject(ctxt->context, len);
Owen Taylor3473f882001-02-23 17:55:21 +00009053 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009054
Owen Taylor3473f882001-02-23 17:55:21 +00009055 CAST_TO_NUMBER;
9056 CHECK_TYPE(XPATH_NUMBER);
9057 start = valuePop(ctxt);
9058 in = start->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009059 xmlXPathReleaseObject(ctxt->context, start);
Owen Taylor3473f882001-02-23 17:55:21 +00009060 CAST_TO_STRING;
9061 CHECK_TYPE(XPATH_STRING);
9062 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00009063 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00009064
Daniel Veillard97ac1312001-05-30 19:14:17 +00009065 /*
9066 * If last pos not present, calculate last position
9067 */
Daniel Veillard9e412302002-06-10 15:59:44 +00009068 if (nargs != 3) {
9069 le = (double)m;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009070 if (in < 1.0)
Daniel Veillard9e412302002-06-10 15:59:44 +00009071 in = 1.0;
9072 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009073
Daniel Veillard45490ae2008-07-29 09:13:19 +00009074 /* Need to check for the special cases where either
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009075 * the index is NaN, the length is NaN, or both
9076 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00009077 */
Daniel Veillard48b3eb22009-03-25 09:51:19 +00009078 if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009079 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00009080 * To meet the requirements of the spec, the arguments
Daniel Veillard45490ae2008-07-29 09:13:19 +00009081 * must be converted to integer format before
Daniel Veillard9e412302002-06-10 15:59:44 +00009082 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009083 *
Daniel Veillard9e412302002-06-10 15:59:44 +00009084 * First we go to integer form, rounding up
9085 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009086 */
9087 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00009088 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00009089
Daniel Veillard9e412302002-06-10 15:59:44 +00009090 if (xmlXPathIsInf(le) == 1) {
9091 l = m;
9092 if (i < 1)
9093 i = 1;
9094 }
9095 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9096 l = 0;
9097 else {
9098 l = (int) le;
9099 if (((double)l)+0.5 <= le) l++;
9100 }
9101
9102 /* Now we normalize inidices */
9103 i -= 1;
9104 l += i;
9105 if (i < 0)
9106 i = 0;
9107 if (l > m)
9108 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00009109
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009110 /* number of chars to copy */
9111 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00009112
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009113 ret = xmlUTF8Strsub(str->stringval, i, l);
9114 }
9115 else {
9116 ret = NULL;
9117 }
Owen Taylor3473f882001-02-23 17:55:21 +00009118 if (ret == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009119 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00009120 else {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009121 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009122 xmlFree(ret);
9123 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009124 xmlXPathReleaseObject(ctxt->context, str);
Owen Taylor3473f882001-02-23 17:55:21 +00009125}
9126
9127/**
9128 * xmlXPathSubstringBeforeFunction:
9129 * @ctxt: the XPath Parser context
9130 * @nargs: the number of arguments
9131 *
9132 * Implement the substring-before() XPath function
9133 * string substring-before(string, string)
9134 * The substring-before function returns the substring of the first
9135 * argument string that precedes the first occurrence of the second
9136 * argument string in the first argument string, or the empty string
9137 * if the first argument string does not contain the second argument
9138 * string. For example, substring-before("1999/04/01","/") returns 1999.
9139 */
9140void
9141xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9142 xmlXPathObjectPtr str;
9143 xmlXPathObjectPtr find;
Daniel Veillardade10f22012-07-12 09:43:27 +08009144 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009145 const xmlChar *point;
9146 int offset;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009147
Owen Taylor3473f882001-02-23 17:55:21 +00009148 CHECK_ARITY(2);
9149 CAST_TO_STRING;
9150 find = valuePop(ctxt);
9151 CAST_TO_STRING;
9152 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009153
Daniel Veillardade10f22012-07-12 09:43:27 +08009154 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009155 if (target) {
9156 point = xmlStrstr(str->stringval, find->stringval);
9157 if (point) {
9158 offset = (int)(point - str->stringval);
Daniel Veillardade10f22012-07-12 09:43:27 +08009159 xmlBufAdd(target, str->stringval, offset);
Owen Taylor3473f882001-02-23 17:55:21 +00009160 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009161 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009162 xmlBufContent(target)));
9163 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009164 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009165 xmlXPathReleaseObject(ctxt->context, str);
9166 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009167}
9168
9169/**
9170 * xmlXPathSubstringAfterFunction:
9171 * @ctxt: the XPath Parser context
9172 * @nargs: the number of arguments
9173 *
9174 * Implement the substring-after() XPath function
9175 * string substring-after(string, string)
9176 * The substring-after function returns the substring of the first
9177 * argument string that follows the first occurrence of the second
9178 * argument string in the first argument string, or the empty stringi
9179 * if the first argument string does not contain the second argument
9180 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9181 * and substring-after("1999/04/01","19") returns 99/04/01.
9182 */
9183void
9184xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9185 xmlXPathObjectPtr str;
9186 xmlXPathObjectPtr find;
Daniel Veillardade10f22012-07-12 09:43:27 +08009187 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009188 const xmlChar *point;
9189 int offset;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009190
Owen Taylor3473f882001-02-23 17:55:21 +00009191 CHECK_ARITY(2);
9192 CAST_TO_STRING;
9193 find = valuePop(ctxt);
9194 CAST_TO_STRING;
9195 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009196
Daniel Veillardade10f22012-07-12 09:43:27 +08009197 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009198 if (target) {
9199 point = xmlStrstr(str->stringval, find->stringval);
9200 if (point) {
9201 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
Daniel Veillardade10f22012-07-12 09:43:27 +08009202 xmlBufAdd(target, &str->stringval[offset],
Owen Taylor3473f882001-02-23 17:55:21 +00009203 xmlStrlen(str->stringval) - offset);
9204 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009205 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009206 xmlBufContent(target)));
9207 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009208 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009209 xmlXPathReleaseObject(ctxt->context, str);
9210 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009211}
9212
9213/**
9214 * xmlXPathNormalizeFunction:
9215 * @ctxt: the XPath Parser context
9216 * @nargs: the number of arguments
9217 *
9218 * Implement the normalize-space() XPath function
9219 * string normalize-space(string?)
9220 * The normalize-space function returns the argument string with white
9221 * space normalized by stripping leading and trailing whitespace
9222 * and replacing sequences of whitespace characters by a single
9223 * space. Whitespace characters are the same allowed by the S production
9224 * in XML. If the argument is omitted, it defaults to the context
9225 * node converted to a string, in other words the value of the context node.
9226 */
9227void
9228xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9229 xmlXPathObjectPtr obj = NULL;
9230 xmlChar *source = NULL;
Daniel Veillardade10f22012-07-12 09:43:27 +08009231 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009232 xmlChar blank;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009233
Daniel Veillarda82b1822004-11-08 16:24:57 +00009234 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009235 if (nargs == 0) {
9236 /* Use current context node */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009237 valuePush(ctxt,
9238 xmlXPathCacheWrapString(ctxt->context,
9239 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00009240 nargs = 1;
9241 }
9242
9243 CHECK_ARITY(1);
9244 CAST_TO_STRING;
9245 CHECK_TYPE(XPATH_STRING);
9246 obj = valuePop(ctxt);
9247 source = obj->stringval;
9248
Daniel Veillardade10f22012-07-12 09:43:27 +08009249 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009250 if (target && source) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00009251
Owen Taylor3473f882001-02-23 17:55:21 +00009252 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00009253 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00009254 source++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009255
Owen Taylor3473f882001-02-23 17:55:21 +00009256 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9257 blank = 0;
9258 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00009259 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009260 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00009261 } else {
9262 if (blank) {
Daniel Veillardade10f22012-07-12 09:43:27 +08009263 xmlBufAdd(target, &blank, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00009264 blank = 0;
9265 }
Daniel Veillardade10f22012-07-12 09:43:27 +08009266 xmlBufAdd(target, source, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00009267 }
9268 source++;
9269 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009270 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009271 xmlBufContent(target)));
9272 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009273 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009274 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00009275}
9276
9277/**
9278 * xmlXPathTranslateFunction:
9279 * @ctxt: the XPath Parser context
9280 * @nargs: the number of arguments
9281 *
9282 * Implement the translate() XPath function
9283 * string translate(string, string, string)
9284 * The translate function returns the first argument string with
9285 * occurrences of characters in the second argument string replaced
9286 * by the character at the corresponding position in the third argument
9287 * string. For example, translate("bar","abc","ABC") returns the string
9288 * BAr. If there is a character in the second argument string with no
9289 * character at a corresponding position in the third argument string
9290 * (because the second argument string is longer than the third argument
9291 * string), then occurrences of that character in the first argument
9292 * string are removed. For example, translate("--aaa--","abc-","ABC")
9293 * returns "AAA". If a character occurs more than once in second
9294 * argument string, then the first occurrence determines the replacement
9295 * character. If the third argument string is longer than the second
9296 * argument string, then excess characters are ignored.
9297 */
9298void
9299xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00009300 xmlXPathObjectPtr str;
9301 xmlXPathObjectPtr from;
9302 xmlXPathObjectPtr to;
Daniel Veillardade10f22012-07-12 09:43:27 +08009303 xmlBufPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009304 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009305 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00009306 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009307 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00009308
Daniel Veillarde043ee12001-04-16 14:08:07 +00009309 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00009310
Daniel Veillarde043ee12001-04-16 14:08:07 +00009311 CAST_TO_STRING;
9312 to = valuePop(ctxt);
9313 CAST_TO_STRING;
9314 from = valuePop(ctxt);
9315 CAST_TO_STRING;
9316 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009317
Daniel Veillardade10f22012-07-12 09:43:27 +08009318 target = xmlBufCreate();
Daniel Veillarde043ee12001-04-16 14:08:07 +00009319 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009320 max = xmlUTF8Strlen(to->stringval);
9321 for (cptr = str->stringval; (ch=*cptr); ) {
9322 offset = xmlUTF8Strloc(from->stringval, cptr);
9323 if (offset >= 0) {
9324 if (offset < max) {
9325 point = xmlUTF8Strpos(to->stringval, offset);
9326 if (point)
Daniel Veillardade10f22012-07-12 09:43:27 +08009327 xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
Daniel Veillard97ac1312001-05-30 19:14:17 +00009328 }
9329 } else
Daniel Veillardade10f22012-07-12 09:43:27 +08009330 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
Daniel Veillard97ac1312001-05-30 19:14:17 +00009331
9332 /* Step to next character in input */
9333 cptr++;
9334 if ( ch & 0x80 ) {
9335 /* if not simple ascii, verify proper format */
9336 if ( (ch & 0xc0) != 0xc0 ) {
9337 xmlGenericError(xmlGenericErrorContext,
9338 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08009339 /* not asserting an XPath error is probably better */
Daniel Veillard97ac1312001-05-30 19:14:17 +00009340 break;
9341 }
9342 /* then skip over remaining bytes for this char */
9343 while ( (ch <<= 1) & 0x80 )
9344 if ( (*cptr++ & 0xc0) != 0x80 ) {
9345 xmlGenericError(xmlGenericErrorContext,
9346 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08009347 /* not asserting an XPath error is probably better */
Daniel Veillard97ac1312001-05-30 19:14:17 +00009348 break;
9349 }
9350 if (ch & 0x80) /* must have had error encountered */
9351 break;
9352 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00009353 }
Owen Taylor3473f882001-02-23 17:55:21 +00009354 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009355 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009356 xmlBufContent(target)));
9357 xmlBufFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009358 xmlXPathReleaseObject(ctxt->context, str);
9359 xmlXPathReleaseObject(ctxt->context, from);
9360 xmlXPathReleaseObject(ctxt->context, to);
Owen Taylor3473f882001-02-23 17:55:21 +00009361}
9362
9363/**
9364 * xmlXPathBooleanFunction:
9365 * @ctxt: the XPath Parser context
9366 * @nargs: the number of arguments
9367 *
9368 * Implement the boolean() XPath function
9369 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00009370 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00009371 * - a number is true if and only if it is neither positive or
9372 * negative zero nor NaN
9373 * - a node-set is true if and only if it is non-empty
9374 * - a string is true if and only if its length is non-zero
9375 */
9376void
9377xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9378 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00009379
9380 CHECK_ARITY(1);
9381 cur = valuePop(ctxt);
9382 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009383 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009384 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009385}
9386
9387/**
9388 * xmlXPathNotFunction:
9389 * @ctxt: the XPath Parser context
9390 * @nargs: the number of arguments
9391 *
9392 * Implement the not() XPath function
9393 * boolean not(boolean)
9394 * The not function returns true if its argument is false,
9395 * and false otherwise.
9396 */
9397void
9398xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9399 CHECK_ARITY(1);
9400 CAST_TO_BOOLEAN;
9401 CHECK_TYPE(XPATH_BOOLEAN);
9402 ctxt->value->boolval = ! ctxt->value->boolval;
9403}
9404
9405/**
9406 * xmlXPathTrueFunction:
9407 * @ctxt: the XPath Parser context
9408 * @nargs: the number of arguments
9409 *
9410 * Implement the true() XPath function
9411 * boolean true()
9412 */
9413void
9414xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9415 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009416 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009417}
9418
9419/**
9420 * xmlXPathFalseFunction:
9421 * @ctxt: the XPath Parser context
9422 * @nargs: the number of arguments
9423 *
9424 * Implement the false() XPath function
9425 * boolean false()
9426 */
9427void
9428xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9429 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009430 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009431}
9432
9433/**
9434 * xmlXPathLangFunction:
9435 * @ctxt: the XPath Parser context
9436 * @nargs: the number of arguments
9437 *
9438 * Implement the lang() XPath function
9439 * boolean lang(string)
9440 * The lang function returns true or false depending on whether the
9441 * language of the context node as specified by xml:lang attributes
9442 * is the same as or is a sublanguage of the language specified by
9443 * the argument string. The language of the context node is determined
9444 * by the value of the xml:lang attribute on the context node, or, if
9445 * the context node has no xml:lang attribute, by the value of the
9446 * xml:lang attribute on the nearest ancestor of the context node that
9447 * has an xml:lang attribute. If there is no such attribute, then lang
9448 * returns false. If there is such an attribute, then lang returns
9449 * true if the attribute value is equal to the argument ignoring case,
9450 * or if there is some suffix starting with - such that the attribute
9451 * value is equal to the argument ignoring that suffix of the attribute
9452 * value and ignoring case.
9453 */
9454void
9455xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009456 xmlXPathObjectPtr val = NULL;
9457 const xmlChar *theLang = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009458 const xmlChar *lang;
9459 int ret = 0;
9460 int i;
9461
9462 CHECK_ARITY(1);
9463 CAST_TO_STRING;
9464 CHECK_TYPE(XPATH_STRING);
9465 val = valuePop(ctxt);
9466 lang = val->stringval;
9467 theLang = xmlNodeGetLang(ctxt->context->node);
9468 if ((theLang != NULL) && (lang != NULL)) {
9469 for (i = 0;lang[i] != 0;i++)
9470 if (toupper(lang[i]) != toupper(theLang[i]))
9471 goto not_equal;
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009472 if ((theLang[i] == 0) || (theLang[i] == '-'))
9473 ret = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009474 }
9475not_equal:
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009476 if (theLang != NULL)
9477 xmlFree((void *)theLang);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009478
9479 xmlXPathReleaseObject(ctxt->context, val);
9480 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009481}
9482
9483/**
9484 * xmlXPathNumberFunction:
9485 * @ctxt: the XPath Parser context
9486 * @nargs: the number of arguments
9487 *
9488 * Implement the number() XPath function
9489 * number number(object?)
9490 */
9491void
9492xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9493 xmlXPathObjectPtr cur;
9494 double res;
9495
Daniel Veillarda82b1822004-11-08 16:24:57 +00009496 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009497 if (nargs == 0) {
9498 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009499 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
Owen Taylor3473f882001-02-23 17:55:21 +00009500 } else {
9501 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9502
9503 res = xmlXPathStringEvalNumber(content);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009504 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
Owen Taylor3473f882001-02-23 17:55:21 +00009505 xmlFree(content);
9506 }
9507 return;
9508 }
9509
9510 CHECK_ARITY(1);
9511 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009512 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00009513}
9514
9515/**
9516 * xmlXPathSumFunction:
9517 * @ctxt: the XPath Parser context
9518 * @nargs: the number of arguments
9519 *
9520 * Implement the sum() XPath function
9521 * number sum(node-set)
9522 * The sum function returns the sum of the values of the nodes in
9523 * the argument node-set.
9524 */
9525void
9526xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9527 xmlXPathObjectPtr cur;
9528 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009529 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00009530
9531 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009532 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009533 ((ctxt->value->type != XPATH_NODESET) &&
9534 (ctxt->value->type != XPATH_XSLT_TREE)))
9535 XP_ERROR(XPATH_INVALID_TYPE);
9536 cur = valuePop(ctxt);
9537
William M. Brack08171912003-12-29 02:52:11 +00009538 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009539 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9540 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00009541 }
9542 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009543 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9544 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009545}
9546
William M. Brack3d426662005-04-19 14:40:28 +00009547/*
9548 * To assure working code on multiple platforms, we want to only depend
9549 * upon the characteristic truncation of converting a floating point value
9550 * to an integer. Unfortunately, because of the different storage sizes
9551 * of our internal floating point value (double) and integer (int), we
9552 * can't directly convert (see bug 301162). This macro is a messy
9553 * 'workaround'
9554 */
9555#define XTRUNC(f, v) \
9556 f = fmod((v), INT_MAX); \
9557 f = (v) - (f) + (double)((int)(f));
9558
Owen Taylor3473f882001-02-23 17:55:21 +00009559/**
9560 * xmlXPathFloorFunction:
9561 * @ctxt: the XPath Parser context
9562 * @nargs: the number of arguments
9563 *
9564 * Implement the floor() XPath function
9565 * number floor(number)
9566 * The floor function returns the largest (closest to positive infinity)
9567 * number that is not greater than the argument and that is an integer.
9568 */
9569void
9570xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009571 double f;
9572
Owen Taylor3473f882001-02-23 17:55:21 +00009573 CHECK_ARITY(1);
9574 CAST_TO_NUMBER;
9575 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009576
William M. Brack3d426662005-04-19 14:40:28 +00009577 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009578 if (f != ctxt->value->floatval) {
9579 if (ctxt->value->floatval > 0)
9580 ctxt->value->floatval = f;
9581 else
9582 ctxt->value->floatval = f - 1;
9583 }
Owen Taylor3473f882001-02-23 17:55:21 +00009584}
9585
9586/**
9587 * xmlXPathCeilingFunction:
9588 * @ctxt: the XPath Parser context
9589 * @nargs: the number of arguments
9590 *
9591 * Implement the ceiling() XPath function
9592 * number ceiling(number)
9593 * The ceiling function returns the smallest (closest to negative infinity)
9594 * number that is not less than the argument and that is an integer.
9595 */
9596void
9597xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9598 double f;
9599
9600 CHECK_ARITY(1);
9601 CAST_TO_NUMBER;
9602 CHECK_TYPE(XPATH_NUMBER);
9603
9604#if 0
9605 ctxt->value->floatval = ceil(ctxt->value->floatval);
9606#else
William M. Brack3d426662005-04-19 14:40:28 +00009607 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009608 if (f != ctxt->value->floatval) {
9609 if (ctxt->value->floatval > 0)
9610 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009611 else {
9612 if (ctxt->value->floatval < 0 && f == 0)
9613 ctxt->value->floatval = xmlXPathNZERO;
9614 else
9615 ctxt->value->floatval = f;
9616 }
9617
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009618 }
Owen Taylor3473f882001-02-23 17:55:21 +00009619#endif
9620}
9621
9622/**
9623 * xmlXPathRoundFunction:
9624 * @ctxt: the XPath Parser context
9625 * @nargs: the number of arguments
9626 *
9627 * Implement the round() XPath function
9628 * number round(number)
9629 * The round function returns the number that is closest to the
9630 * argument and that is an integer. If there are two such numbers,
9631 * then the one that is even is returned.
9632 */
9633void
9634xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9635 double f;
9636
9637 CHECK_ARITY(1);
9638 CAST_TO_NUMBER;
9639 CHECK_TYPE(XPATH_NUMBER);
9640
Daniel Veillardcda96922001-08-21 10:56:31 +00009641 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9642 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9643 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009644 (ctxt->value->floatval == 0.0))
9645 return;
9646
William M. Brack3d426662005-04-19 14:40:28 +00009647 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009648 if (ctxt->value->floatval < 0) {
9649 if (ctxt->value->floatval < f - 0.5)
9650 ctxt->value->floatval = f - 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009651 else
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009652 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009653 if (ctxt->value->floatval == 0)
9654 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009655 } else {
9656 if (ctxt->value->floatval < f + 0.5)
9657 ctxt->value->floatval = f;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009658 else
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009659 ctxt->value->floatval = f + 1;
9660 }
Owen Taylor3473f882001-02-23 17:55:21 +00009661}
9662
9663/************************************************************************
9664 * *
9665 * The Parser *
9666 * *
9667 ************************************************************************/
9668
9669/*
William M. Brack08171912003-12-29 02:52:11 +00009670 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00009671 * implementation.
9672 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009673static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009674static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009675static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009676static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00009677static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9678 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00009679
9680/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00009681 * xmlXPathCurrentChar:
9682 * @ctxt: the XPath parser context
9683 * @cur: pointer to the beginning of the char
9684 * @len: pointer to the length of the char read
9685 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009686 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00009687 * bytes in the input buffer.
9688 *
Daniel Veillard60087f32001-10-10 09:45:09 +00009689 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00009690 */
9691
9692static int
9693xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9694 unsigned char c;
9695 unsigned int val;
9696 const xmlChar *cur;
9697
9698 if (ctxt == NULL)
9699 return(0);
9700 cur = ctxt->cur;
9701
9702 /*
9703 * We are supposed to handle UTF8, check it's valid
9704 * From rfc2044: encoding of the Unicode values on UTF-8:
9705 *
9706 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9707 * 0000 0000-0000 007F 0xxxxxxx
9708 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
Daniel Veillard45490ae2008-07-29 09:13:19 +00009709 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
Daniel Veillard61d80a22001-04-27 17:13:01 +00009710 *
9711 * Check for the 0x110000 limit too
9712 */
9713 c = *cur;
9714 if (c & 0x80) {
9715 if ((cur[1] & 0xc0) != 0x80)
9716 goto encoding_error;
9717 if ((c & 0xe0) == 0xe0) {
9718
9719 if ((cur[2] & 0xc0) != 0x80)
9720 goto encoding_error;
9721 if ((c & 0xf0) == 0xf0) {
9722 if (((c & 0xf8) != 0xf0) ||
9723 ((cur[3] & 0xc0) != 0x80))
9724 goto encoding_error;
9725 /* 4-byte code */
9726 *len = 4;
9727 val = (cur[0] & 0x7) << 18;
9728 val |= (cur[1] & 0x3f) << 12;
9729 val |= (cur[2] & 0x3f) << 6;
9730 val |= cur[3] & 0x3f;
9731 } else {
9732 /* 3-byte code */
9733 *len = 3;
9734 val = (cur[0] & 0xf) << 12;
9735 val |= (cur[1] & 0x3f) << 6;
9736 val |= cur[2] & 0x3f;
9737 }
9738 } else {
9739 /* 2-byte code */
9740 *len = 2;
9741 val = (cur[0] & 0x1f) << 6;
9742 val |= cur[1] & 0x3f;
9743 }
9744 if (!IS_CHAR(val)) {
9745 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009746 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00009747 return(val);
9748 } else {
9749 /* 1-byte code */
9750 *len = 1;
9751 return((int) *cur);
9752 }
9753encoding_error:
9754 /*
William M. Brack08171912003-12-29 02:52:11 +00009755 * If we detect an UTF8 error that probably means that the
9756 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00009757 * declaration header. Report the error and switch the encoding
9758 * to ISO-Latin-1 (if you don't like this policy, just declare the
9759 * encoding !)
9760 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00009761 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00009762 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009763}
9764
9765/**
Owen Taylor3473f882001-02-23 17:55:21 +00009766 * xmlXPathParseNCName:
9767 * @ctxt: the XPath Parser context
9768 *
9769 * parse an XML namespace non qualified name.
9770 *
9771 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9772 *
9773 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9774 * CombiningChar | Extender
9775 *
9776 * Returns the namespace name or NULL
9777 */
9778
9779xmlChar *
9780xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00009781 const xmlChar *in;
9782 xmlChar *ret;
9783 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009784
Daniel Veillarda82b1822004-11-08 16:24:57 +00009785 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00009786 /*
9787 * Accelerator for simple ASCII names
9788 */
9789 in = ctxt->cur;
9790 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9791 ((*in >= 0x41) && (*in <= 0x5A)) ||
9792 (*in == '_')) {
9793 in++;
9794 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9795 ((*in >= 0x41) && (*in <= 0x5A)) ||
9796 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00009797 (*in == '_') || (*in == '.') ||
9798 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00009799 in++;
9800 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9801 (*in == '[') || (*in == ']') || (*in == ':') ||
9802 (*in == '@') || (*in == '*')) {
9803 count = in - ctxt->cur;
9804 if (count == 0)
9805 return(NULL);
9806 ret = xmlStrndup(ctxt->cur, count);
9807 ctxt->cur = in;
9808 return(ret);
9809 }
9810 }
9811 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009812}
9813
Daniel Veillard2156a562001-04-28 12:24:34 +00009814
Owen Taylor3473f882001-02-23 17:55:21 +00009815/**
9816 * xmlXPathParseQName:
9817 * @ctxt: the XPath Parser context
Daniel Veillard45490ae2008-07-29 09:13:19 +00009818 * @prefix: a xmlChar **
Owen Taylor3473f882001-02-23 17:55:21 +00009819 *
9820 * parse an XML qualified name
9821 *
9822 * [NS 5] QName ::= (Prefix ':')? LocalPart
9823 *
9824 * [NS 6] Prefix ::= NCName
9825 *
9826 * [NS 7] LocalPart ::= NCName
9827 *
9828 * Returns the function returns the local part, and prefix is updated
9829 * to get the Prefix if any.
9830 */
9831
Daniel Veillard56a4cb82001-03-24 17:00:36 +00009832static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00009833xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9834 xmlChar *ret = NULL;
9835
9836 *prefix = NULL;
9837 ret = xmlXPathParseNCName(ctxt);
Daniel Veillard074f37e2008-09-01 13:38:22 +00009838 if (ret && CUR == ':') {
Owen Taylor3473f882001-02-23 17:55:21 +00009839 *prefix = ret;
9840 NEXT;
9841 ret = xmlXPathParseNCName(ctxt);
9842 }
9843 return(ret);
9844}
9845
9846/**
9847 * xmlXPathParseName:
9848 * @ctxt: the XPath Parser context
9849 *
9850 * parse an XML name
9851 *
9852 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9853 * CombiningChar | Extender
9854 *
9855 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9856 *
9857 * Returns the namespace name or NULL
9858 */
9859
9860xmlChar *
9861xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009862 const xmlChar *in;
9863 xmlChar *ret;
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009864 size_t count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009865
Daniel Veillarda82b1822004-11-08 16:24:57 +00009866 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009867 /*
9868 * Accelerator for simple ASCII names
9869 */
9870 in = ctxt->cur;
9871 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9872 ((*in >= 0x41) && (*in <= 0x5A)) ||
9873 (*in == '_') || (*in == ':')) {
9874 in++;
9875 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9876 ((*in >= 0x41) && (*in <= 0x5A)) ||
9877 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00009878 (*in == '_') || (*in == '-') ||
9879 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00009880 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00009881 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009882 count = in - ctxt->cur;
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009883 if (count > XML_MAX_NAME_LENGTH) {
9884 ctxt->cur = in;
9885 XP_ERRORNULL(XPATH_EXPR_ERROR);
9886 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00009887 ret = xmlStrndup(ctxt->cur, count);
9888 ctxt->cur = in;
9889 return(ret);
9890 }
9891 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009892 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009893}
9894
Daniel Veillard61d80a22001-04-27 17:13:01 +00009895static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00009896xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009897 xmlChar buf[XML_MAX_NAMELEN + 5];
9898 int len = 0, l;
9899 int c;
9900
9901 /*
9902 * Handler for more complex cases
9903 */
9904 c = CUR_CHAR(l);
9905 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00009906 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9907 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00009908 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00009909 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009910 return(NULL);
9911 }
9912
9913 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9914 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9915 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00009916 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009917 (IS_COMBINING(c)) ||
9918 (IS_EXTENDER(c)))) {
9919 COPY_BUF(l,buf,len,c);
9920 NEXTL(l);
9921 c = CUR_CHAR(l);
9922 if (len >= XML_MAX_NAMELEN) {
9923 /*
9924 * Okay someone managed to make a huge name, so he's ready to pay
9925 * for the processing speed.
9926 */
9927 xmlChar *buffer;
9928 int max = len * 2;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009929
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009930 if (len > XML_MAX_NAME_LENGTH) {
9931 XP_ERRORNULL(XPATH_EXPR_ERROR);
9932 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00009933 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009934 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009935 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009936 }
9937 memcpy(buffer, buf, len);
9938 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9939 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00009940 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009941 (IS_COMBINING(c)) ||
9942 (IS_EXTENDER(c))) {
9943 if (len + 10 > max) {
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009944 if (max > XML_MAX_NAME_LENGTH) {
9945 XP_ERRORNULL(XPATH_EXPR_ERROR);
9946 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00009947 max *= 2;
9948 buffer = (xmlChar *) xmlRealloc(buffer,
9949 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009950 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009951 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009952 }
9953 }
9954 COPY_BUF(l,buffer,len,c);
9955 NEXTL(l);
9956 c = CUR_CHAR(l);
9957 }
9958 buffer[len] = 0;
9959 return(buffer);
9960 }
9961 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009962 if (len == 0)
9963 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009964 return(xmlStrndup(buf, len));
9965}
Daniel Veillard3cd72402002-05-13 10:33:30 +00009966
9967#define MAX_FRAC 20
9968
William M. Brack372a4452004-02-17 13:09:23 +00009969/*
9970 * These are used as divisors for the fractional part of a number.
9971 * Since the table includes 1.0 (representing '0' fractional digits),
9972 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
9973 */
9974static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +00009975 1.0, 10.0, 100.0, 1000.0, 10000.0,
9976 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
9977 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
9978 100000000000000.0,
9979 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +00009980 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +00009981};
9982
Owen Taylor3473f882001-02-23 17:55:21 +00009983/**
9984 * xmlXPathStringEvalNumber:
9985 * @str: A string to scan
9986 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00009987 * [30a] Float ::= Number ('e' Digits?)?
9988 *
Owen Taylor3473f882001-02-23 17:55:21 +00009989 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard45490ae2008-07-29 09:13:19 +00009990 * | '.' Digits
Owen Taylor3473f882001-02-23 17:55:21 +00009991 * [31] Digits ::= [0-9]+
9992 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009993 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00009994 * In complement of the Number expression, this function also handles
9995 * negative values : '-' Number.
9996 *
9997 * Returns the double value.
9998 */
9999double
10000xmlXPathStringEvalNumber(const xmlChar *str) {
10001 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +000010002 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010003 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010004 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010005 int exponent = 0;
10006 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010007#ifdef __GNUC__
10008 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010009 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010010#endif
Daniel Veillardeca82812002-04-24 11:42:02 +000010011 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +000010012 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010013 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
10014 return(xmlXPathNAN);
10015 }
10016 if (*cur == '-') {
10017 isneg = 1;
10018 cur++;
10019 }
Daniel Veillardb06c6142001-08-27 14:26:30 +000010020
10021#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010022 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010023 * tmp/temp is a workaround against a gcc compiler bug
10024 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010025 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010026 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010027 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010028 ret = ret * 10;
10029 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +000010030 ok = 1;
10031 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +000010032 temp = (double) tmp;
10033 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010034 }
Daniel Veillardb06c6142001-08-27 14:26:30 +000010035#else
Daniel Veillard7b416132002-03-07 08:36:03 +000010036 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010037 while ((*cur >= '0') && (*cur <= '9')) {
10038 ret = ret * 10 + (*cur - '0');
10039 ok = 1;
10040 cur++;
10041 }
10042#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010043
Owen Taylor3473f882001-02-23 17:55:21 +000010044 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +000010045 int v, frac = 0;
10046 double fraction = 0;
10047
Owen Taylor3473f882001-02-23 17:55:21 +000010048 cur++;
10049 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10050 return(xmlXPathNAN);
10051 }
Daniel Veillard3cd72402002-05-13 10:33:30 +000010052 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
10053 v = (*cur - '0');
10054 fraction = fraction * 10 + v;
10055 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010056 cur++;
10057 }
Daniel Veillard3cd72402002-05-13 10:33:30 +000010058 fraction /= my_pow10[frac];
10059 ret = ret + fraction;
10060 while ((*cur >= '0') && (*cur <= '9'))
10061 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010062 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010063 if ((*cur == 'e') || (*cur == 'E')) {
10064 cur++;
10065 if (*cur == '-') {
10066 is_exponent_negative = 1;
10067 cur++;
William M. Brack99127052004-05-24 02:52:28 +000010068 } else if (*cur == '+') {
10069 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010070 }
10071 while ((*cur >= '0') && (*cur <= '9')) {
10072 exponent = exponent * 10 + (*cur - '0');
10073 cur++;
10074 }
10075 }
William M. Brack76e95df2003-10-18 16:20:14 +000010076 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010077 if (*cur != 0) return(xmlXPathNAN);
10078 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010079 if (is_exponent_negative) exponent = -exponent;
10080 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +000010081 return(ret);
10082}
10083
10084/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010085 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +000010086 * @ctxt: the XPath Parser context
10087 *
10088 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard45490ae2008-07-29 09:13:19 +000010089 * | '.' Digits
Owen Taylor3473f882001-02-23 17:55:21 +000010090 * [31] Digits ::= [0-9]+
10091 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010092 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +000010093 *
10094 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010095static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010096xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10097{
Owen Taylor3473f882001-02-23 17:55:21 +000010098 double ret = 0.0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010099 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010100 int exponent = 0;
10101 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010102#ifdef __GNUC__
10103 unsigned long tmp = 0;
10104 double temp;
10105#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010106
10107 CHECK_ERROR;
10108 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10109 XP_ERROR(XPATH_NUMBER_ERROR);
10110 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010111#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010112 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010113 * tmp/temp is a workaround against a gcc compiler bug
10114 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010115 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010116 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010117 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010118 ret = ret * 10;
10119 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010120 ok = 1;
10121 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +000010122 temp = (double) tmp;
10123 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010124 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010125#else
10126 ret = 0;
10127 while ((CUR >= '0') && (CUR <= '9')) {
10128 ret = ret * 10 + (CUR - '0');
10129 ok = 1;
10130 NEXT;
10131 }
10132#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010133 if (CUR == '.') {
Phil Shaferee32ad32010-11-03 20:53:55 +010010134 int v, frac = 0;
10135 double fraction = 0;
10136
Owen Taylor3473f882001-02-23 17:55:21 +000010137 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010138 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10139 XP_ERROR(XPATH_NUMBER_ERROR);
10140 }
Phil Shaferee32ad32010-11-03 20:53:55 +010010141 while ((CUR >= '0') && (CUR <= '9') && (frac < MAX_FRAC)) {
10142 v = (CUR - '0');
10143 fraction = fraction * 10 + v;
10144 frac = frac + 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010145 NEXT;
10146 }
Phil Shaferee32ad32010-11-03 20:53:55 +010010147 fraction /= my_pow10[frac];
10148 ret = ret + fraction;
10149 while ((CUR >= '0') && (CUR <= '9'))
10150 NEXT;
Owen Taylor3473f882001-02-23 17:55:21 +000010151 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010152 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010153 NEXT;
10154 if (CUR == '-') {
10155 is_exponent_negative = 1;
10156 NEXT;
William M. Brack99127052004-05-24 02:52:28 +000010157 } else if (CUR == '+') {
10158 NEXT;
10159 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010160 while ((CUR >= '0') && (CUR <= '9')) {
10161 exponent = exponent * 10 + (CUR - '0');
10162 NEXT;
10163 }
10164 if (is_exponent_negative)
10165 exponent = -exponent;
10166 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +000010167 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010168 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010169 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010170}
10171
10172/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010173 * xmlXPathParseLiteral:
10174 * @ctxt: the XPath Parser context
10175 *
10176 * Parse a Literal
10177 *
10178 * [29] Literal ::= '"' [^"]* '"'
10179 * | "'" [^']* "'"
10180 *
10181 * Returns the value found or NULL in case of error
10182 */
10183static xmlChar *
10184xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10185 const xmlChar *q;
10186 xmlChar *ret = NULL;
10187
10188 if (CUR == '"') {
10189 NEXT;
10190 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010191 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010192 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010193 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010194 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010195 } else {
10196 ret = xmlStrndup(q, CUR_PTR - q);
10197 NEXT;
10198 }
10199 } else if (CUR == '\'') {
10200 NEXT;
10201 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010202 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010203 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010204 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010205 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010206 } else {
10207 ret = xmlStrndup(q, CUR_PTR - q);
10208 NEXT;
10209 }
10210 } else {
Daniel Veillard24505b02005-07-28 23:49:35 +000010211 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010212 }
10213 return(ret);
10214}
10215
10216/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010217 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +000010218 * @ctxt: the XPath Parser context
10219 *
10220 * Parse a Literal and push it on the stack.
10221 *
10222 * [29] Literal ::= '"' [^"]* '"'
10223 * | "'" [^']* "'"
10224 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010225 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +000010226 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010227static void
10228xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010229 const xmlChar *q;
10230 xmlChar *ret = NULL;
10231
10232 if (CUR == '"') {
10233 NEXT;
10234 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010235 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +000010236 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010237 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010238 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10239 } else {
10240 ret = xmlStrndup(q, CUR_PTR - q);
10241 NEXT;
10242 }
10243 } else if (CUR == '\'') {
10244 NEXT;
10245 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010246 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +000010247 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010248 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010249 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10250 } else {
10251 ret = xmlStrndup(q, CUR_PTR - q);
10252 NEXT;
10253 }
10254 } else {
10255 XP_ERROR(XPATH_START_LITERAL_ERROR);
10256 }
10257 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010258 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010259 xmlXPathCacheNewString(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010260 xmlFree(ret);
10261}
10262
10263/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010264 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +000010265 * @ctxt: the XPath Parser context
10266 *
10267 * Parse a VariableReference, evaluate it and push it on the stack.
10268 *
10269 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +000010270 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +000010271 * of any of the types that are possible for the value of an expression,
10272 * and may also be of additional types not specified here.
10273 *
10274 * Early evaluation is possible since:
10275 * The variable bindings [...] used to evaluate a subexpression are
Daniel Veillard45490ae2008-07-29 09:13:19 +000010276 * always the same as those used to evaluate the containing expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010277 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010278 * [36] VariableReference ::= '$' QName
Owen Taylor3473f882001-02-23 17:55:21 +000010279 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010280static void
10281xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010282 xmlChar *name;
10283 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010284
10285 SKIP_BLANKS;
10286 if (CUR != '$') {
10287 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10288 }
10289 NEXT;
10290 name = xmlXPathParseQName(ctxt, &prefix);
10291 if (name == NULL) {
10292 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10293 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010294 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010295 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10296 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010297 SKIP_BLANKS;
Daniel Veillardb3d14912005-09-04 20:47:39 +000010298 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10299 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
10300 }
Owen Taylor3473f882001-02-23 17:55:21 +000010301}
10302
10303/**
10304 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +000010305 * @name: a name string
10306 *
10307 * Is the name given a NodeType one.
10308 *
10309 * [38] NodeType ::= 'comment'
10310 * | 'text'
10311 * | 'processing-instruction'
10312 * | 'node'
10313 *
10314 * Returns 1 if true 0 otherwise
10315 */
10316int
10317xmlXPathIsNodeType(const xmlChar *name) {
10318 if (name == NULL)
10319 return(0);
10320
Daniel Veillard1971ee22002-01-31 20:29:19 +000010321 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +000010322 return(1);
10323 if (xmlStrEqual(name, BAD_CAST "text"))
10324 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010325 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +000010326 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010327 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +000010328 return(1);
10329 return(0);
10330}
10331
10332/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010333 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +000010334 * @ctxt: the XPath Parser context
10335 *
10336 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010337 * [17] Argument ::= Expr
Owen Taylor3473f882001-02-23 17:55:21 +000010338 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010339 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +000010340 * pushed on the stack
10341 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010342static void
10343xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010344 xmlChar *name;
10345 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010346 int nbargs = 0;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010347 int sort = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010348
10349 name = xmlXPathParseQName(ctxt, &prefix);
10350 if (name == NULL) {
Daniel Veillard074f37e2008-09-01 13:38:22 +000010351 xmlFree(prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010352 XP_ERROR(XPATH_EXPR_ERROR);
10353 }
10354 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010355#ifdef DEBUG_EXPR
10356 if (prefix == NULL)
10357 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10358 name);
10359 else
10360 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10361 prefix, name);
10362#endif
10363
Owen Taylor3473f882001-02-23 17:55:21 +000010364 if (CUR != '(') {
10365 XP_ERROR(XPATH_EXPR_ERROR);
10366 }
10367 NEXT;
10368 SKIP_BLANKS;
10369
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010370 /*
10371 * Optimization for count(): we don't need the node-set to be sorted.
10372 */
10373 if ((prefix == NULL) && (name[0] == 'c') &&
10374 xmlStrEqual(name, BAD_CAST "count"))
10375 {
10376 sort = 0;
10377 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010378 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +000010379 if (CUR != ')') {
10380 while (CUR != 0) {
10381 int op1 = ctxt->comp->last;
10382 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010383 xmlXPathCompileExpr(ctxt, sort);
Daniel Veillard074f37e2008-09-01 13:38:22 +000010384 if (ctxt->error != XPATH_EXPRESSION_OK) {
10385 xmlFree(name);
10386 xmlFree(prefix);
10387 return;
10388 }
Daniel Veillard71f9d732003-01-14 16:07:16 +000010389 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10390 nbargs++;
10391 if (CUR == ')') break;
10392 if (CUR != ',') {
10393 XP_ERROR(XPATH_EXPR_ERROR);
10394 }
10395 NEXT;
10396 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010397 }
Owen Taylor3473f882001-02-23 17:55:21 +000010398 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010399 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10400 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010401 NEXT;
10402 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010403}
10404
10405/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010406 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010407 * @ctxt: the XPath Parser context
10408 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010409 * [15] PrimaryExpr ::= VariableReference
Owen Taylor3473f882001-02-23 17:55:21 +000010410 * | '(' Expr ')'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010411 * | Literal
10412 * | Number
10413 * | FunctionCall
Owen Taylor3473f882001-02-23 17:55:21 +000010414 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010415 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010416 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010417static void
10418xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010419 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010420 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010421 else if (CUR == '(') {
10422 NEXT;
10423 SKIP_BLANKS;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010424 xmlXPathCompileExpr(ctxt, 1);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010425 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000010426 if (CUR != ')') {
10427 XP_ERROR(XPATH_EXPR_ERROR);
10428 }
10429 NEXT;
10430 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010431 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010432 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010433 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010434 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010435 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010436 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010437 }
10438 SKIP_BLANKS;
10439}
10440
10441/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010442 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010443 * @ctxt: the XPath Parser context
10444 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010445 * [20] FilterExpr ::= PrimaryExpr
10446 * | FilterExpr Predicate
Owen Taylor3473f882001-02-23 17:55:21 +000010447 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010448 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010449 * Square brackets are used to filter expressions in the same way that
10450 * they are used in location paths. It is an error if the expression to
10451 * be filtered does not evaluate to a node-set. The context node list
10452 * used for evaluating the expression in square brackets is the node-set
10453 * to be filtered listed in document order.
10454 */
10455
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010456static void
10457xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10458 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010459 CHECK_ERROR;
10460 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010461
Owen Taylor3473f882001-02-23 17:55:21 +000010462 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010463 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +000010464 SKIP_BLANKS;
10465 }
10466
Daniel Veillard45490ae2008-07-29 09:13:19 +000010467
Owen Taylor3473f882001-02-23 17:55:21 +000010468}
10469
10470/**
10471 * xmlXPathScanName:
10472 * @ctxt: the XPath Parser context
10473 *
10474 * Trickery: parse an XML name but without consuming the input flow
10475 * Needed to avoid insanity in the parser state.
10476 *
10477 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10478 * CombiningChar | Extender
10479 *
10480 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10481 *
10482 * [6] Names ::= Name (S Name)*
10483 *
10484 * Returns the Name parsed or NULL
10485 */
10486
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010487static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +000010488xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +000010489 int len = 0, l;
10490 int c;
Daniel Veillard03226812004-11-01 14:55:21 +000010491 const xmlChar *cur;
10492 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +000010493
Daniel Veillard03226812004-11-01 14:55:21 +000010494 cur = ctxt->cur;
10495
10496 c = CUR_CHAR(l);
10497 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10498 (!IS_LETTER(c) && (c != '_') &&
10499 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010500 return(NULL);
10501 }
10502
Daniel Veillard03226812004-11-01 14:55:21 +000010503 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10504 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10505 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000010506 (c == '_') || (c == ':') ||
Daniel Veillard03226812004-11-01 14:55:21 +000010507 (IS_COMBINING(c)) ||
10508 (IS_EXTENDER(c)))) {
10509 len += l;
10510 NEXTL(l);
10511 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +000010512 }
Daniel Veillard03226812004-11-01 14:55:21 +000010513 ret = xmlStrndup(cur, ctxt->cur - cur);
10514 ctxt->cur = cur;
10515 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +000010516}
10517
10518/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010519 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010520 * @ctxt: the XPath Parser context
10521 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010522 * [19] PathExpr ::= LocationPath
10523 * | FilterExpr
10524 * | FilterExpr '/' RelativeLocationPath
10525 * | FilterExpr '//' RelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000010526 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010527 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010528 * The / operator and // operators combine an arbitrary expression
10529 * and a relative location path. It is an error if the expression
10530 * does not evaluate to a node-set.
10531 * The / operator does composition in the same way as when / is
10532 * used in a location path. As in location paths, // is short for
10533 * /descendant-or-self::node()/.
10534 */
10535
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010536static void
10537xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010538 int lc = 1; /* Should we branch to LocationPath ? */
10539 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10540
10541 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010542 if ((CUR == '$') || (CUR == '(') ||
10543 (IS_ASCII_DIGIT(CUR)) ||
William M. Brackd1757ab2004-10-02 22:07:48 +000010544 (CUR == '\'') || (CUR == '"') ||
10545 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010546 lc = 0;
10547 } else if (CUR == '*') {
10548 /* relative or absolute location path */
10549 lc = 1;
10550 } else if (CUR == '/') {
10551 /* relative or absolute location path */
10552 lc = 1;
10553 } else if (CUR == '@') {
10554 /* relative abbreviated attribute location path */
10555 lc = 1;
10556 } else if (CUR == '.') {
10557 /* relative abbreviated attribute location path */
10558 lc = 1;
10559 } else {
10560 /*
10561 * Problem is finding if we have a name here whether it's:
10562 * - a nodetype
10563 * - a function call in which case it's followed by '('
10564 * - an axis in which case it's followed by ':'
10565 * - a element name
10566 * We do an a priori analysis here rather than having to
10567 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +000010568 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +000010569 * read/write/debug.
10570 */
10571 SKIP_BLANKS;
10572 name = xmlXPathScanName(ctxt);
10573 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10574#ifdef DEBUG_STEP
10575 xmlGenericError(xmlGenericErrorContext,
10576 "PathExpr: Axis\n");
10577#endif
10578 lc = 1;
10579 xmlFree(name);
10580 } else if (name != NULL) {
10581 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +000010582
Daniel Veillard45490ae2008-07-29 09:13:19 +000010583
Owen Taylor3473f882001-02-23 17:55:21 +000010584 while (NXT(len) != 0) {
10585 if (NXT(len) == '/') {
10586 /* element name */
10587#ifdef DEBUG_STEP
10588 xmlGenericError(xmlGenericErrorContext,
10589 "PathExpr: AbbrRelLocation\n");
10590#endif
10591 lc = 1;
10592 break;
William M. Brack76e95df2003-10-18 16:20:14 +000010593 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +000010594 /* ignore blanks */
10595 ;
Owen Taylor3473f882001-02-23 17:55:21 +000010596 } else if (NXT(len) == ':') {
10597#ifdef DEBUG_STEP
10598 xmlGenericError(xmlGenericErrorContext,
10599 "PathExpr: AbbrRelLocation\n");
10600#endif
10601 lc = 1;
10602 break;
10603 } else if ((NXT(len) == '(')) {
10604 /* Note Type or Function */
10605 if (xmlXPathIsNodeType(name)) {
10606#ifdef DEBUG_STEP
10607 xmlGenericError(xmlGenericErrorContext,
10608 "PathExpr: Type search\n");
10609#endif
10610 lc = 1;
10611 } else {
10612#ifdef DEBUG_STEP
10613 xmlGenericError(xmlGenericErrorContext,
10614 "PathExpr: function call\n");
10615#endif
10616 lc = 0;
10617 }
10618 break;
10619 } else if ((NXT(len) == '[')) {
10620 /* element name */
10621#ifdef DEBUG_STEP
10622 xmlGenericError(xmlGenericErrorContext,
10623 "PathExpr: AbbrRelLocation\n");
10624#endif
10625 lc = 1;
10626 break;
10627 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10628 (NXT(len) == '=')) {
10629 lc = 1;
10630 break;
10631 } else {
10632 lc = 1;
10633 break;
10634 }
10635 len++;
10636 }
10637 if (NXT(len) == 0) {
10638#ifdef DEBUG_STEP
10639 xmlGenericError(xmlGenericErrorContext,
10640 "PathExpr: AbbrRelLocation\n");
10641#endif
10642 /* element name */
10643 lc = 1;
10644 }
10645 xmlFree(name);
10646 } else {
William M. Brack08171912003-12-29 02:52:11 +000010647 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +000010648 XP_ERROR(XPATH_EXPR_ERROR);
10649 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000010650 }
Owen Taylor3473f882001-02-23 17:55:21 +000010651
10652 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010653 if (CUR == '/') {
10654 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10655 } else {
10656 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010657 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010658 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010659 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010660 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010661 CHECK_ERROR;
10662 if ((CUR == '/') && (NXT(1) == '/')) {
10663 SKIP(2);
10664 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010665
10666 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10667 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10668 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10669
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010670 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010671 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010672 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010673 }
10674 }
10675 SKIP_BLANKS;
10676}
10677
10678/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010679 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010680 * @ctxt: the XPath Parser context
10681 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010682 * [18] UnionExpr ::= PathExpr
10683 * | UnionExpr '|' PathExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010684 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010685 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010686 */
10687
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010688static void
10689xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10690 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010691 CHECK_ERROR;
10692 SKIP_BLANKS;
10693 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010694 int op1 = ctxt->comp->last;
10695 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010696
10697 NEXT;
10698 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010699 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010700
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010701 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10702
Owen Taylor3473f882001-02-23 17:55:21 +000010703 SKIP_BLANKS;
10704 }
Owen Taylor3473f882001-02-23 17:55:21 +000010705}
10706
10707/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010708 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010709 * @ctxt: the XPath Parser context
10710 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010711 * [27] UnaryExpr ::= UnionExpr
10712 * | '-' UnaryExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010713 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010714 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010715 */
10716
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010717static void
10718xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010719 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010720 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010721
10722 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +000010723 while (CUR == '-') {
10724 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010725 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010726 NEXT;
10727 SKIP_BLANKS;
10728 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010729
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010730 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010731 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010732 if (found) {
10733 if (minus)
10734 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10735 else
10736 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010737 }
10738}
10739
10740/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010741 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010742 * @ctxt: the XPath Parser context
10743 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010744 * [26] MultiplicativeExpr ::= UnaryExpr
10745 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10746 * | MultiplicativeExpr 'div' UnaryExpr
10747 * | MultiplicativeExpr 'mod' UnaryExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010748 * [34] MultiplyOperator ::= '*'
10749 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010750 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010751 */
10752
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010753static void
10754xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10755 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010756 CHECK_ERROR;
10757 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010758 while ((CUR == '*') ||
Owen Taylor3473f882001-02-23 17:55:21 +000010759 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10760 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10761 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010762 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010763
10764 if (CUR == '*') {
10765 op = 0;
10766 NEXT;
10767 } else if (CUR == 'd') {
10768 op = 1;
10769 SKIP(3);
10770 } else if (CUR == 'm') {
10771 op = 2;
10772 SKIP(3);
10773 }
10774 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010775 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010776 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010777 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010778 SKIP_BLANKS;
10779 }
10780}
10781
10782/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010783 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010784 * @ctxt: the XPath Parser context
10785 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010786 * [25] AdditiveExpr ::= MultiplicativeExpr
10787 * | AdditiveExpr '+' MultiplicativeExpr
10788 * | AdditiveExpr '-' MultiplicativeExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010789 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010790 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010791 */
10792
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010793static void
10794xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010795
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010796 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010797 CHECK_ERROR;
10798 SKIP_BLANKS;
10799 while ((CUR == '+') || (CUR == '-')) {
10800 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010801 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010802
10803 if (CUR == '+') plus = 1;
10804 else plus = 0;
10805 NEXT;
10806 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010807 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010808 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010809 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010810 SKIP_BLANKS;
10811 }
10812}
10813
10814/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010815 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010816 * @ctxt: the XPath Parser context
10817 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010818 * [24] RelationalExpr ::= AdditiveExpr
10819 * | RelationalExpr '<' AdditiveExpr
10820 * | RelationalExpr '>' AdditiveExpr
10821 * | RelationalExpr '<=' AdditiveExpr
10822 * | RelationalExpr '>=' AdditiveExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010823 *
10824 * A <= B > C is allowed ? Answer from James, yes with
10825 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10826 * which is basically what got implemented.
10827 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010828 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +000010829 * on the stack
10830 */
10831
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010832static void
10833xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10834 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010835 CHECK_ERROR;
10836 SKIP_BLANKS;
10837 while ((CUR == '<') ||
10838 (CUR == '>') ||
10839 ((CUR == '<') && (NXT(1) == '=')) ||
10840 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010841 int inf, strict;
10842 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010843
10844 if (CUR == '<') inf = 1;
10845 else inf = 0;
10846 if (NXT(1) == '=') strict = 0;
10847 else strict = 1;
10848 NEXT;
10849 if (!strict) NEXT;
10850 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010851 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010852 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010853 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +000010854 SKIP_BLANKS;
10855 }
10856}
10857
10858/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010859 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010860 * @ctxt: the XPath Parser context
10861 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010862 * [23] EqualityExpr ::= RelationalExpr
10863 * | EqualityExpr '=' RelationalExpr
10864 * | EqualityExpr '!=' RelationalExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010865 *
10866 * A != B != C is allowed ? Answer from James, yes with
10867 * (RelationalExpr = RelationalExpr) = RelationalExpr
10868 * (RelationalExpr != RelationalExpr) != RelationalExpr
10869 * which is basically what got implemented.
10870 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010871 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010872 *
10873 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010874static void
10875xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10876 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010877 CHECK_ERROR;
10878 SKIP_BLANKS;
10879 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010880 int eq;
10881 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010882
10883 if (CUR == '=') eq = 1;
10884 else eq = 0;
10885 NEXT;
10886 if (!eq) NEXT;
10887 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010888 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010889 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010890 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010891 SKIP_BLANKS;
10892 }
10893}
10894
10895/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010896 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010897 * @ctxt: the XPath Parser context
10898 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010899 * [22] AndExpr ::= EqualityExpr
10900 * | AndExpr 'and' EqualityExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010901 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010902 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010903 *
10904 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010905static void
10906xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10907 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010908 CHECK_ERROR;
10909 SKIP_BLANKS;
10910 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010911 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010912 SKIP(3);
10913 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010914 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010915 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010916 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010917 SKIP_BLANKS;
10918 }
10919}
10920
10921/**
Daniel Veillard591b4be2003-02-09 23:33:36 +000010922 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010923 * @ctxt: the XPath Parser context
10924 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010925 * [14] Expr ::= OrExpr
10926 * [21] OrExpr ::= AndExpr
10927 * | OrExpr 'or' AndExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010928 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010929 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +000010930 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010931static void
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010932xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010933 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010934 CHECK_ERROR;
10935 SKIP_BLANKS;
10936 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010937 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010938 SKIP(2);
10939 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010940 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010941 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010942 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010943 SKIP_BLANKS;
10944 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010945 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010946 /* more ops could be optimized too */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010947 /*
10948 * This is the main place to eliminate sorting for
10949 * operations which don't require a sorted node-set.
10950 * E.g. count().
10951 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010952 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10953 }
Owen Taylor3473f882001-02-23 17:55:21 +000010954}
10955
10956/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010957 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +000010958 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010959 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +000010960 *
10961 * [8] Predicate ::= '[' PredicateExpr ']'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010962 * [9] PredicateExpr ::= Expr
Owen Taylor3473f882001-02-23 17:55:21 +000010963 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010964 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +000010965 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010966static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010967xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010968 int op1 = ctxt->comp->last;
10969
10970 SKIP_BLANKS;
10971 if (CUR != '[') {
10972 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10973 }
10974 NEXT;
10975 SKIP_BLANKS;
10976
10977 ctxt->comp->last = -1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000010978 /*
10979 * This call to xmlXPathCompileExpr() will deactivate sorting
10980 * of the predicate result.
10981 * TODO: Sorting is still activated for filters, since I'm not
10982 * sure if needed. Normally sorting should not be needed, since
10983 * a filter can only diminish the number of items in a sequence,
10984 * but won't change its order; so if the initial sequence is sorted,
10985 * subsequent sorting is not needed.
10986 */
10987 if (! filter)
10988 xmlXPathCompileExpr(ctxt, 0);
10989 else
10990 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010991 CHECK_ERROR;
10992
10993 if (CUR != ']') {
10994 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10995 }
10996
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010997 if (filter)
10998 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10999 else
11000 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011001
11002 NEXT;
11003 SKIP_BLANKS;
11004}
11005
11006/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011007 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +000011008 * @ctxt: the XPath Parser context
11009 * @test: pointer to a xmlXPathTestVal
11010 * @type: pointer to a xmlXPathTypeVal
11011 * @prefix: placeholder for a possible name prefix
11012 *
11013 * [7] NodeTest ::= NameTest
11014 * | NodeType '(' ')'
11015 * | 'processing-instruction' '(' Literal ')'
11016 *
11017 * [37] NameTest ::= '*'
11018 * | NCName ':' '*'
11019 * | QName
11020 * [38] NodeType ::= 'comment'
11021 * | 'text'
11022 * | 'processing-instruction'
11023 * | 'node'
11024 *
William M. Brack08171912003-12-29 02:52:11 +000011025 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +000011026 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011027static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011028xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11029 xmlXPathTypeVal *type, const xmlChar **prefix,
11030 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +000011031 int blanks;
11032
11033 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11034 STRANGE;
11035 return(NULL);
11036 }
William M. Brack78637da2003-07-31 14:47:38 +000011037 *type = (xmlXPathTypeVal) 0;
11038 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011039 *prefix = NULL;
11040 SKIP_BLANKS;
11041
11042 if ((name == NULL) && (CUR == '*')) {
11043 /*
11044 * All elements
11045 */
11046 NEXT;
11047 *test = NODE_TEST_ALL;
11048 return(NULL);
11049 }
11050
11051 if (name == NULL)
11052 name = xmlXPathParseNCName(ctxt);
11053 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011054 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011055 }
11056
William M. Brack76e95df2003-10-18 16:20:14 +000011057 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +000011058 SKIP_BLANKS;
11059 if (CUR == '(') {
11060 NEXT;
11061 /*
11062 * NodeType or PI search
11063 */
11064 if (xmlStrEqual(name, BAD_CAST "comment"))
11065 *type = NODE_TYPE_COMMENT;
11066 else if (xmlStrEqual(name, BAD_CAST "node"))
11067 *type = NODE_TYPE_NODE;
11068 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11069 *type = NODE_TYPE_PI;
11070 else if (xmlStrEqual(name, BAD_CAST "text"))
11071 *type = NODE_TYPE_TEXT;
11072 else {
11073 if (name != NULL)
11074 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000011075 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011076 }
11077
11078 *test = NODE_TEST_TYPE;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011079
Owen Taylor3473f882001-02-23 17:55:21 +000011080 SKIP_BLANKS;
11081 if (*type == NODE_TYPE_PI) {
11082 /*
11083 * Specific case: search a PI by name.
11084 */
Owen Taylor3473f882001-02-23 17:55:21 +000011085 if (name != NULL)
11086 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +000011087 name = NULL;
11088 if (CUR != ')') {
11089 name = xmlXPathParseLiteral(ctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000011090 CHECK_ERROR NULL;
Daniel Veillarded23b7d2002-05-27 12:16:02 +000011091 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +000011092 SKIP_BLANKS;
11093 }
Owen Taylor3473f882001-02-23 17:55:21 +000011094 }
11095 if (CUR != ')') {
11096 if (name != NULL)
11097 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000011098 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011099 }
11100 NEXT;
11101 return(name);
11102 }
11103 *test = NODE_TEST_NAME;
11104 if ((!blanks) && (CUR == ':')) {
11105 NEXT;
11106
11107 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011108 * Since currently the parser context don't have a
11109 * namespace list associated:
11110 * The namespace name for this prefix can be computed
11111 * only at evaluation time. The compilation is done
11112 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +000011113 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011114#if 0
Owen Taylor3473f882001-02-23 17:55:21 +000011115 *prefix = xmlXPathNsLookup(ctxt->context, name);
11116 if (name != NULL)
11117 xmlFree(name);
11118 if (*prefix == NULL) {
11119 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11120 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011121#else
11122 *prefix = name;
11123#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011124
11125 if (CUR == '*') {
11126 /*
11127 * All elements
11128 */
11129 NEXT;
11130 *test = NODE_TEST_ALL;
11131 return(NULL);
11132 }
11133
11134 name = xmlXPathParseNCName(ctxt);
11135 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011136 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011137 }
11138 }
11139 return(name);
11140}
11141
11142/**
11143 * xmlXPathIsAxisName:
11144 * @name: a preparsed name token
11145 *
11146 * [6] AxisName ::= 'ancestor'
11147 * | 'ancestor-or-self'
11148 * | 'attribute'
11149 * | 'child'
11150 * | 'descendant'
11151 * | 'descendant-or-self'
11152 * | 'following'
11153 * | 'following-sibling'
11154 * | 'namespace'
11155 * | 'parent'
11156 * | 'preceding'
11157 * | 'preceding-sibling'
11158 * | 'self'
11159 *
11160 * Returns the axis or 0
11161 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011162static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +000011163xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +000011164 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011165 switch (name[0]) {
11166 case 'a':
11167 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11168 ret = AXIS_ANCESTOR;
11169 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11170 ret = AXIS_ANCESTOR_OR_SELF;
11171 if (xmlStrEqual(name, BAD_CAST "attribute"))
11172 ret = AXIS_ATTRIBUTE;
11173 break;
11174 case 'c':
11175 if (xmlStrEqual(name, BAD_CAST "child"))
11176 ret = AXIS_CHILD;
11177 break;
11178 case 'd':
11179 if (xmlStrEqual(name, BAD_CAST "descendant"))
11180 ret = AXIS_DESCENDANT;
11181 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11182 ret = AXIS_DESCENDANT_OR_SELF;
11183 break;
11184 case 'f':
11185 if (xmlStrEqual(name, BAD_CAST "following"))
11186 ret = AXIS_FOLLOWING;
11187 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11188 ret = AXIS_FOLLOWING_SIBLING;
11189 break;
11190 case 'n':
11191 if (xmlStrEqual(name, BAD_CAST "namespace"))
11192 ret = AXIS_NAMESPACE;
11193 break;
11194 case 'p':
11195 if (xmlStrEqual(name, BAD_CAST "parent"))
11196 ret = AXIS_PARENT;
11197 if (xmlStrEqual(name, BAD_CAST "preceding"))
11198 ret = AXIS_PRECEDING;
11199 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11200 ret = AXIS_PRECEDING_SIBLING;
11201 break;
11202 case 's':
11203 if (xmlStrEqual(name, BAD_CAST "self"))
11204 ret = AXIS_SELF;
11205 break;
11206 }
11207 return(ret);
11208}
11209
11210/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011211 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +000011212 * @ctxt: the XPath Parser context
11213 *
11214 * [4] Step ::= AxisSpecifier NodeTest Predicate*
Daniel Veillard45490ae2008-07-29 09:13:19 +000011215 * | AbbreviatedStep
Owen Taylor3473f882001-02-23 17:55:21 +000011216 *
11217 * [12] AbbreviatedStep ::= '.' | '..'
11218 *
11219 * [5] AxisSpecifier ::= AxisName '::'
11220 * | AbbreviatedAxisSpecifier
11221 *
11222 * [13] AbbreviatedAxisSpecifier ::= '@'?
11223 *
11224 * Modified for XPtr range support as:
11225 *
11226 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11227 * | AbbreviatedStep
11228 * | 'range-to' '(' Expr ')' Predicate*
11229 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011230 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +000011231 * A location step of . is short for self::node(). This is
11232 * particularly useful in conjunction with //. For example, the
11233 * location path .//para is short for
11234 * self::node()/descendant-or-self::node()/child::para
11235 * and so will select all para descendant elements of the context
11236 * node.
11237 * Similarly, a location step of .. is short for parent::node().
11238 * For example, ../title is short for parent::node()/child::title
11239 * and so will select the title children of the parent of the context
11240 * node.
11241 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011242static void
11243xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011244#ifdef LIBXML_XPTR_ENABLED
11245 int rangeto = 0;
11246 int op2 = -1;
11247#endif
11248
Owen Taylor3473f882001-02-23 17:55:21 +000011249 SKIP_BLANKS;
11250 if ((CUR == '.') && (NXT(1) == '.')) {
11251 SKIP(2);
11252 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011253 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11254 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011255 } else if (CUR == '.') {
11256 NEXT;
11257 SKIP_BLANKS;
11258 } else {
11259 xmlChar *name = NULL;
11260 const xmlChar *prefix = NULL;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011261 xmlXPathTestVal test = (xmlXPathTestVal) 0;
William M. Brack78637da2003-07-31 14:47:38 +000011262 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011263 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011264 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +000011265
11266 /*
11267 * The modification needed for XPointer change to the production
11268 */
11269#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011270 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +000011271 name = xmlXPathParseNCName(ctxt);
11272 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011273 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011274 xmlFree(name);
11275 SKIP_BLANKS;
11276 if (CUR != '(') {
11277 XP_ERROR(XPATH_EXPR_ERROR);
11278 }
11279 NEXT;
11280 SKIP_BLANKS;
11281
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011282 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011283 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +000011284 CHECK_ERROR;
11285
11286 SKIP_BLANKS;
11287 if (CUR != ')') {
11288 XP_ERROR(XPATH_EXPR_ERROR);
11289 }
11290 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011291 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000011292 goto eval_predicates;
11293 }
11294 }
11295#endif
Daniel Veillard2156a562001-04-28 12:24:34 +000011296 if (CUR == '*') {
11297 axis = AXIS_CHILD;
11298 } else {
11299 if (name == NULL)
11300 name = xmlXPathParseNCName(ctxt);
11301 if (name != NULL) {
11302 axis = xmlXPathIsAxisName(name);
11303 if (axis != 0) {
11304 SKIP_BLANKS;
11305 if ((CUR == ':') && (NXT(1) == ':')) {
11306 SKIP(2);
11307 xmlFree(name);
11308 name = NULL;
11309 } else {
11310 /* an element name can conflict with an axis one :-\ */
11311 axis = AXIS_CHILD;
11312 }
Owen Taylor3473f882001-02-23 17:55:21 +000011313 } else {
Owen Taylor3473f882001-02-23 17:55:21 +000011314 axis = AXIS_CHILD;
11315 }
Daniel Veillard2156a562001-04-28 12:24:34 +000011316 } else if (CUR == '@') {
11317 NEXT;
11318 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +000011319 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +000011320 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +000011321 }
Owen Taylor3473f882001-02-23 17:55:21 +000011322 }
11323
Daniel Veillard2f3523f2010-10-15 18:30:29 +020011324 if (ctxt->error != XPATH_EXPRESSION_OK) {
11325 xmlFree(name);
11326 return;
11327 }
Owen Taylor3473f882001-02-23 17:55:21 +000011328
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011329 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +000011330 if (test == 0)
11331 return;
11332
Daniel Veillarded6c5492005-07-23 15:00:22 +000011333 if ((prefix != NULL) && (ctxt->context != NULL) &&
11334 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11335 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11336 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11337 }
11338 }
Owen Taylor3473f882001-02-23 17:55:21 +000011339#ifdef DEBUG_STEP
11340 xmlGenericError(xmlGenericErrorContext,
11341 "Basis : computing new set\n");
11342#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011343
Owen Taylor3473f882001-02-23 17:55:21 +000011344#ifdef DEBUG_STEP
11345 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011346 if (ctxt->value == NULL)
11347 xmlGenericError(xmlGenericErrorContext, "no value\n");
11348 else if (ctxt->value->nodesetval == NULL)
11349 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11350 else
11351 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011352#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011353
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011354#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +000011355eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011356#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011357 op1 = ctxt->comp->last;
11358 ctxt->comp->last = -1;
11359
Owen Taylor3473f882001-02-23 17:55:21 +000011360 SKIP_BLANKS;
11361 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011362 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011363 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011364
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011365#ifdef LIBXML_XPTR_ENABLED
11366 if (rangeto) {
11367 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11368 } else
11369#endif
11370 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11371 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011372
Owen Taylor3473f882001-02-23 17:55:21 +000011373 }
11374#ifdef DEBUG_STEP
11375 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011376 if (ctxt->value == NULL)
11377 xmlGenericError(xmlGenericErrorContext, "no value\n");
11378 else if (ctxt->value->nodesetval == NULL)
11379 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11380 else
11381 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11382 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011383#endif
11384}
11385
11386/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011387 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011388 * @ctxt: the XPath Parser context
11389 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011390 * [3] RelativeLocationPath ::= Step
11391 * | RelativeLocationPath '/' Step
11392 * | AbbreviatedRelativeLocationPath
11393 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
Owen Taylor3473f882001-02-23 17:55:21 +000011394 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011395 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +000011396 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011397static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011398xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011399(xmlXPathParserContextPtr ctxt) {
11400 SKIP_BLANKS;
11401 if ((CUR == '/') && (NXT(1) == '/')) {
11402 SKIP(2);
11403 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011404 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11405 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011406 } else if (CUR == '/') {
11407 NEXT;
11408 SKIP_BLANKS;
11409 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011410 xmlXPathCompStep(ctxt);
Martin729601f2009-10-12 22:42:26 +020011411 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000011412 SKIP_BLANKS;
11413 while (CUR == '/') {
11414 if ((CUR == '/') && (NXT(1) == '/')) {
11415 SKIP(2);
11416 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011417 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +000011418 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011419 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011420 } else if (CUR == '/') {
11421 NEXT;
11422 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011423 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011424 }
11425 SKIP_BLANKS;
11426 }
11427}
11428
11429/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011430 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011431 * @ctxt: the XPath Parser context
11432 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011433 * [1] LocationPath ::= RelativeLocationPath
11434 * | AbsoluteLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011435 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
Daniel Veillard45490ae2008-07-29 09:13:19 +000011436 * | AbbreviatedAbsoluteLocationPath
11437 * [10] AbbreviatedAbsoluteLocationPath ::=
11438 * '//' RelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011439 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011440 * Compile a location path
11441 *
Owen Taylor3473f882001-02-23 17:55:21 +000011442 * // is short for /descendant-or-self::node()/. For example,
11443 * //para is short for /descendant-or-self::node()/child::para and
11444 * so will select any para element in the document (even a para element
11445 * that is a document element will be selected by //para since the
11446 * document element node is a child of the root node); div//para is
11447 * short for div/descendant-or-self::node()/child::para and so will
11448 * select all para descendants of div children.
11449 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011450static void
11451xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000011452 SKIP_BLANKS;
11453 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011454 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011455 } else {
11456 while (CUR == '/') {
11457 if ((CUR == '/') && (NXT(1) == '/')) {
11458 SKIP(2);
11459 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011460 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11461 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011462 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011463 } else if (CUR == '/') {
11464 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +000011465 SKIP_BLANKS;
11466 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +000011467 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +000011468 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011469 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011470 }
Martin729601f2009-10-12 22:42:26 +020011471 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000011472 }
11473 }
11474}
11475
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011476/************************************************************************
11477 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011478 * XPath precompiled expression evaluation *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011479 * *
11480 ************************************************************************/
11481
Daniel Veillardf06307e2001-07-03 10:35:50 +000011482static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011483xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11484
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011485#ifdef DEBUG_STEP
11486static void
Daniel Veillard074f37e2008-09-01 13:38:22 +000011487xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011488 int nbNodes)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011489{
Daniel Veillardf06307e2001-07-03 10:35:50 +000011490 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillard074f37e2008-09-01 13:38:22 +000011491 switch (op->value) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011492 case AXIS_ANCESTOR:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011493 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011494 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011495 case AXIS_ANCESTOR_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011496 xmlGenericError(xmlGenericErrorContext,
11497 "axis 'ancestors-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011498 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011499 case AXIS_ATTRIBUTE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011500 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011501 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011502 case AXIS_CHILD:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011503 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011504 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011505 case AXIS_DESCENDANT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011506 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011507 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011508 case AXIS_DESCENDANT_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011509 xmlGenericError(xmlGenericErrorContext,
11510 "axis 'descendant-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011511 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011512 case AXIS_FOLLOWING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011513 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011514 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011515 case AXIS_FOLLOWING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011516 xmlGenericError(xmlGenericErrorContext,
11517 "axis 'following-siblings' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011518 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011519 case AXIS_NAMESPACE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011520 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011521 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011522 case AXIS_PARENT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011523 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011524 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011525 case AXIS_PRECEDING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011526 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011527 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011528 case AXIS_PRECEDING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011529 xmlGenericError(xmlGenericErrorContext,
11530 "axis 'preceding-sibling' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011531 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011532 case AXIS_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011533 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011534 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011535 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011536 xmlGenericError(xmlGenericErrorContext,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011537 " context contains %d nodes\n", nbNodes);
Daniel Veillard074f37e2008-09-01 13:38:22 +000011538 switch (op->value2) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011539 case NODE_TEST_NONE:
11540 xmlGenericError(xmlGenericErrorContext,
11541 " searching for none !!!\n");
11542 break;
11543 case NODE_TEST_TYPE:
11544 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011545 " searching for type %d\n", op->value3);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011546 break;
11547 case NODE_TEST_PI:
11548 xmlGenericError(xmlGenericErrorContext,
11549 " searching for PI !!!\n");
11550 break;
11551 case NODE_TEST_ALL:
11552 xmlGenericError(xmlGenericErrorContext,
11553 " searching for *\n");
11554 break;
11555 case NODE_TEST_NS:
11556 xmlGenericError(xmlGenericErrorContext,
11557 " searching for namespace %s\n",
Daniel Veillard074f37e2008-09-01 13:38:22 +000011558 op->value5);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011559 break;
11560 case NODE_TEST_NAME:
11561 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011562 " searching for name %s\n", op->value5);
11563 if (op->value4)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011564 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011565 " with namespace %s\n", op->value4);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011566 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011567 }
11568 xmlGenericError(xmlGenericErrorContext, "Testing : ");
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011569}
11570#endif /* DEBUG_STEP */
11571
11572static int
11573xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11574 xmlXPathStepOpPtr op,
11575 xmlNodeSetPtr set,
11576 int contextSize,
11577 int hasNsNodes)
11578{
11579 if (op->ch1 != -1) {
11580 xmlXPathCompExprPtr comp = ctxt->comp;
11581 /*
11582 * Process inner predicates first.
11583 */
11584 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11585 /*
11586 * TODO: raise an internal error.
11587 */
11588 }
11589 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11590 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11591 CHECK_ERROR0;
11592 if (contextSize <= 0)
11593 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011594 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011595 if (op->ch2 != -1) {
11596 xmlXPathContextPtr xpctxt = ctxt->context;
11597 xmlNodePtr contextNode, oldContextNode;
11598 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011599 int i, res, contextPos = 0, newContextSize;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011600 xmlXPathStepOpPtr exprOp;
11601 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11602
11603#ifdef LIBXML_XPTR_ENABLED
11604 /*
11605 * URGENT TODO: Check the following:
11606 * We don't expect location sets if evaluating prediates, right?
11607 * Only filters should expect location sets, right?
11608 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011609#endif
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011610 /*
11611 * SPEC XPath 1.0:
11612 * "For each node in the node-set to be filtered, the
11613 * PredicateExpr is evaluated with that node as the
11614 * context node, with the number of nodes in the
11615 * node-set as the context size, and with the proximity
11616 * position of the node in the node-set with respect to
11617 * the axis as the context position;"
11618 * @oldset is the node-set" to be filtered.
11619 *
11620 * SPEC XPath 1.0:
11621 * "only predicates change the context position and
11622 * context size (see [2.4 Predicates])."
11623 * Example:
11624 * node-set context pos
11625 * nA 1
11626 * nB 2
11627 * nC 3
11628 * After applying predicate [position() > 1] :
11629 * node-set context pos
11630 * nB 1
11631 * nC 2
11632 */
11633 oldContextNode = xpctxt->node;
11634 oldContextDoc = xpctxt->doc;
11635 /*
11636 * Get the expression of this predicate.
11637 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000011638 exprOp = &ctxt->comp->steps[op->ch2];
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011639 newContextSize = 0;
11640 for (i = 0; i < set->nodeNr; i++) {
11641 if (set->nodeTab[i] == NULL)
11642 continue;
11643
11644 contextNode = set->nodeTab[i];
11645 xpctxt->node = contextNode;
11646 xpctxt->contextSize = contextSize;
11647 xpctxt->proximityPosition = ++contextPos;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011648
11649 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011650 * Also set the xpath document in case things like
11651 * key() are evaluated in the predicate.
11652 */
11653 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11654 (contextNode->doc != NULL))
11655 xpctxt->doc = contextNode->doc;
11656 /*
11657 * Evaluate the predicate expression with 1 context node
11658 * at a time; this node is packaged into a node set; this
11659 * node set is handed over to the evaluation mechanism.
11660 */
11661 if (contextObj == NULL)
11662 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11663 else
11664 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11665 contextNode);
11666
11667 valuePush(ctxt, contextObj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011668
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011669 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011670
William M. Brack0bcec062007-02-14 02:15:19 +000011671 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11672 xmlXPathNodeSetClear(set, hasNsNodes);
11673 newContextSize = 0;
11674 goto evaluation_exit;
11675 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011676
11677 if (res != 0) {
11678 newContextSize++;
11679 } else {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011680 /*
11681 * Remove the entry from the initial node set.
11682 */
11683 set->nodeTab[i] = NULL;
11684 if (contextNode->type == XML_NAMESPACE_DECL)
11685 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011686 }
11687 if (ctxt->value == contextObj) {
11688 /*
11689 * Don't free the temporary XPath object holding the
11690 * context node, in order to avoid massive recreation
11691 * inside this loop.
11692 */
11693 valuePop(ctxt);
11694 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11695 } else {
11696 /*
11697 * TODO: The object was lost in the evaluation machinery.
11698 * Can this happen? Maybe in internal-error cases.
11699 */
11700 contextObj = NULL;
11701 }
11702 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011703
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011704 if (contextObj != NULL) {
11705 if (ctxt->value == contextObj)
11706 valuePop(ctxt);
11707 xmlXPathReleaseObject(xpctxt, contextObj);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011708 }
William M. Brack0bcec062007-02-14 02:15:19 +000011709evaluation_exit:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011710 if (exprRes != NULL)
11711 xmlXPathReleaseObject(ctxt->context, exprRes);
11712 /*
11713 * Reset/invalidate the context.
11714 */
11715 xpctxt->node = oldContextNode;
11716 xpctxt->doc = oldContextDoc;
11717 xpctxt->contextSize = -1;
11718 xpctxt->proximityPosition = -1;
11719 return(newContextSize);
11720 }
11721 return(contextSize);
11722}
11723
11724static int
11725xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11726 xmlXPathStepOpPtr op,
11727 xmlNodeSetPtr set,
11728 int contextSize,
11729 int minPos,
11730 int maxPos,
11731 int hasNsNodes)
11732{
11733 if (op->ch1 != -1) {
11734 xmlXPathCompExprPtr comp = ctxt->comp;
11735 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11736 /*
11737 * TODO: raise an internal error.
11738 */
11739 }
11740 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11741 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11742 CHECK_ERROR0;
11743 if (contextSize <= 0)
11744 return(0);
11745 }
11746 /*
11747 * Check if the node set contains a sufficient number of nodes for
11748 * the requested range.
11749 */
11750 if (contextSize < minPos) {
11751 xmlXPathNodeSetClear(set, hasNsNodes);
11752 return(0);
11753 }
11754 if (op->ch2 == -1) {
11755 /*
11756 * TODO: Can this ever happen?
11757 */
11758 return (contextSize);
11759 } else {
11760 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011761 int i, pos = 0, newContextSize = 0, contextPos = 0, res;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011762 xmlXPathStepOpPtr exprOp;
11763 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11764 xmlNodePtr oldContextNode, contextNode = NULL;
11765 xmlXPathContextPtr xpctxt = ctxt->context;
Daniel Veillardf5048b32011-08-18 17:10:13 +080011766 int frame;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011767
11768#ifdef LIBXML_XPTR_ENABLED
11769 /*
11770 * URGENT TODO: Check the following:
11771 * We don't expect location sets if evaluating prediates, right?
11772 * Only filters should expect location sets, right?
11773 */
11774#endif /* LIBXML_XPTR_ENABLED */
11775
11776 /*
11777 * Save old context.
11778 */
11779 oldContextNode = xpctxt->node;
11780 oldContextDoc = xpctxt->doc;
11781 /*
11782 * Get the expression of this predicate.
11783 */
11784 exprOp = &ctxt->comp->steps[op->ch2];
11785 for (i = 0; i < set->nodeNr; i++) {
Daniel Veillardf5048b32011-08-18 17:10:13 +080011786 xmlXPathObjectPtr tmp;
11787
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011788 if (set->nodeTab[i] == NULL)
11789 continue;
11790
11791 contextNode = set->nodeTab[i];
11792 xpctxt->node = contextNode;
11793 xpctxt->contextSize = contextSize;
11794 xpctxt->proximityPosition = ++contextPos;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011795
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011796 /*
11797 * Initialize the new set.
11798 * Also set the xpath document in case things like
11799 * key() evaluation are attempted on the predicate
11800 */
11801 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11802 (contextNode->doc != NULL))
11803 xpctxt->doc = contextNode->doc;
11804 /*
11805 * Evaluate the predicate expression with 1 context node
11806 * at a time; this node is packaged into a node set; this
11807 * node set is handed over to the evaluation mechanism.
11808 */
11809 if (contextObj == NULL)
11810 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11811 else
11812 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11813 contextNode);
11814
Daniel Veillardf5048b32011-08-18 17:10:13 +080011815 frame = xmlXPathSetFrame(ctxt);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011816 valuePush(ctxt, contextObj);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011817 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Daniel Veillardf5048b32011-08-18 17:10:13 +080011818 tmp = valuePop(ctxt);
11819 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011820
William M. Brackf1794562007-08-23 12:58:13 +000011821 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
Daniel Veillardf5048b32011-08-18 17:10:13 +080011822 while (tmp != contextObj) {
Daniel Veillarddf83c172010-11-17 14:12:14 +010011823 /*
11824 * Free up the result
11825 * then pop off contextObj, which will be freed later
11826 */
11827 xmlXPathReleaseObject(xpctxt, tmp);
Daniel Veillardf5048b32011-08-18 17:10:13 +080011828 tmp = valuePop(ctxt);
Daniel Veillardfec31bc2010-11-18 11:07:24 +010011829 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011830 goto evaluation_error;
William M. Brackf1794562007-08-23 12:58:13 +000011831 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080011832 /* push the result back onto the stack */
11833 valuePush(ctxt, tmp);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011834
11835 if (res)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011836 pos++;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011837
11838 if (res && (pos >= minPos) && (pos <= maxPos)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011839 /*
11840 * Fits in the requested range.
11841 */
11842 newContextSize++;
11843 if (minPos == maxPos) {
11844 /*
11845 * Only 1 node was requested.
11846 */
11847 if (contextNode->type == XML_NAMESPACE_DECL) {
11848 /*
11849 * As always: take care of those nasty
11850 * namespace nodes.
11851 */
11852 set->nodeTab[i] = NULL;
11853 }
11854 xmlXPathNodeSetClear(set, hasNsNodes);
11855 set->nodeNr = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011856 set->nodeTab[0] = contextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011857 goto evaluation_exit;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011858 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011859 if (pos == maxPos) {
11860 /*
11861 * We are done.
11862 */
11863 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11864 goto evaluation_exit;
11865 }
11866 } else {
11867 /*
11868 * Remove the entry from the initial node set.
11869 */
11870 set->nodeTab[i] = NULL;
11871 if (contextNode->type == XML_NAMESPACE_DECL)
11872 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11873 }
11874 if (exprRes != NULL) {
11875 xmlXPathReleaseObject(ctxt->context, exprRes);
11876 exprRes = NULL;
11877 }
11878 if (ctxt->value == contextObj) {
11879 /*
11880 * Don't free the temporary XPath object holding the
11881 * context node, in order to avoid massive recreation
11882 * inside this loop.
11883 */
11884 valuePop(ctxt);
11885 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11886 } else {
11887 /*
11888 * The object was lost in the evaluation machinery.
11889 * Can this happen? Maybe in case of internal-errors.
11890 */
11891 contextObj = NULL;
11892 }
11893 }
11894 goto evaluation_exit;
11895
11896evaluation_error:
11897 xmlXPathNodeSetClear(set, hasNsNodes);
11898 newContextSize = 0;
11899
11900evaluation_exit:
11901 if (contextObj != NULL) {
11902 if (ctxt->value == contextObj)
11903 valuePop(ctxt);
11904 xmlXPathReleaseObject(xpctxt, contextObj);
11905 }
11906 if (exprRes != NULL)
11907 xmlXPathReleaseObject(ctxt->context, exprRes);
11908 /*
11909 * Reset/invalidate the context.
11910 */
11911 xpctxt->node = oldContextNode;
11912 xpctxt->doc = oldContextDoc;
11913 xpctxt->contextSize = -1;
11914 xpctxt->proximityPosition = -1;
11915 return(newContextSize);
11916 }
11917 return(contextSize);
11918}
11919
11920static int
11921xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
Daniel Veillard45490ae2008-07-29 09:13:19 +000011922 xmlXPathStepOpPtr op,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011923 int *maxPos)
11924{
11925
11926 xmlXPathStepOpPtr exprOp;
11927
11928 /*
11929 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11930 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000011931
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011932 /*
11933 * If not -1, then ch1 will point to:
11934 * 1) For predicates (XPATH_OP_PREDICATE):
11935 * - an inner predicate operator
11936 * 2) For filters (XPATH_OP_FILTER):
11937 * - an inner filter operater OR
11938 * - an expression selecting the node set.
11939 * E.g. "key('a', 'b')" or "(//foo | //bar)".
Daniel Veillard45490ae2008-07-29 09:13:19 +000011940 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011941 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11942 return(0);
11943
11944 if (op->ch2 != -1) {
11945 exprOp = &ctxt->comp->steps[op->ch2];
Daniel Veillard45490ae2008-07-29 09:13:19 +000011946 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011947 return(0);
11948
11949 if ((exprOp != NULL) &&
11950 (exprOp->op == XPATH_OP_VALUE) &&
11951 (exprOp->value4 != NULL) &&
11952 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11953 {
11954 /*
11955 * We have a "[n]" predicate here.
11956 * TODO: Unfortunately this simplistic test here is not
11957 * able to detect a position() predicate in compound
11958 * expressions like "[@attr = 'a" and position() = 1],
11959 * and even not the usage of position() in
11960 * "[position() = 1]"; thus - obviously - a position-range,
11961 * like it "[position() < 5]", is also not detected.
11962 * Maybe we could rewrite the AST to ease the optimization.
11963 */
11964 *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011965
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011966 if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
11967 (float) *maxPos)
Daniel Veillard45490ae2008-07-29 09:13:19 +000011968 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011969 return(1);
11970 }
11971 }
11972 return(0);
11973}
11974
11975static int
11976xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11977 xmlXPathStepOpPtr op,
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011978 xmlNodePtr * first, xmlNodePtr * last,
11979 int toBool)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011980{
11981
11982#define XP_TEST_HIT \
11983 if (hasAxisRange != 0) { \
11984 if (++pos == maxPos) { \
11985 addNode(seq, cur); \
11986 goto axis_range_end; } \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011987 } else { \
11988 addNode(seq, cur); \
11989 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011990
11991#define XP_TEST_HIT_NS \
11992 if (hasAxisRange != 0) { \
11993 if (++pos == maxPos) { \
11994 hasNsNodes = 1; \
11995 xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
11996 goto axis_range_end; } \
11997 } else { \
11998 hasNsNodes = 1; \
11999 xmlXPathNodeSetAddNs(seq, \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012000 xpctxt->node, (xmlNsPtr) cur); \
12001 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012002
12003 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
12004 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12005 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12006 const xmlChar *prefix = op->value4;
12007 const xmlChar *name = op->value5;
12008 const xmlChar *URI = NULL;
12009
12010#ifdef DEBUG_STEP
12011 int nbMatches = 0, prevMatches = 0;
12012#endif
12013 int total = 0, hasNsNodes = 0;
12014 /* The popped object holding the context nodes */
12015 xmlXPathObjectPtr obj;
12016 /* The set of context nodes for the node tests */
12017 xmlNodeSetPtr contextSeq;
12018 int contextIdx;
12019 xmlNodePtr contextNode;
12020 /* The context node for a compound traversal */
12021 xmlNodePtr outerContextNode;
12022 /* The final resulting node set wrt to all context nodes */
12023 xmlNodeSetPtr outSeq;
12024 /*
12025 * The temporary resulting node set wrt 1 context node.
12026 * Used to feed predicate evaluation.
12027 */
12028 xmlNodeSetPtr seq;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012029 xmlNodePtr cur;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012030 /* First predicate operator */
12031 xmlXPathStepOpPtr predOp;
12032 int maxPos; /* The requested position() (when a "[n]" predicate) */
12033 int hasPredicateRange, hasAxisRange, pos, size, newSize;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012034 int breakOnFirstHit;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012035
12036 xmlXPathTraversalFunction next = NULL;
12037 /* compound axis traversal */
12038 xmlXPathTraversalFunctionExt outerNext = NULL;
12039 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12040 xmlXPathNodeSetMergeFunction mergeAndClear;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012041 xmlNodePtr oldContextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012042 xmlXPathContextPtr xpctxt = ctxt->context;
12043
12044
12045 CHECK_TYPE0(XPATH_NODESET);
12046 obj = valuePop(ctxt);
12047 /*
12048 * Setup namespaces.
12049 */
12050 if (prefix != NULL) {
12051 URI = xmlXPathNsLookup(xpctxt, prefix);
12052 if (URI == NULL) {
12053 xmlXPathReleaseObject(xpctxt, obj);
12054 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12055 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012056 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012057 /*
12058 * Setup axis.
12059 *
12060 * MAYBE FUTURE TODO: merging optimizations:
12061 * - If the nodes to be traversed wrt to the initial nodes and
12062 * the current axis cannot overlap, then we could avoid searching
12063 * for duplicates during the merge.
12064 * But the question is how/when to evaluate if they cannot overlap.
12065 * Example: if we know that for two initial nodes, the one is
12066 * not in the ancestor-or-self axis of the other, then we could safely
12067 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12068 * the descendant-or-self axis.
12069 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012070 mergeAndClear = xmlXPathNodeSetMergeAndClear;
12071 switch (axis) {
12072 case AXIS_ANCESTOR:
12073 first = NULL;
12074 next = xmlXPathNextAncestor;
12075 break;
12076 case AXIS_ANCESTOR_OR_SELF:
12077 first = NULL;
12078 next = xmlXPathNextAncestorOrSelf;
12079 break;
12080 case AXIS_ATTRIBUTE:
12081 first = NULL;
12082 last = NULL;
12083 next = xmlXPathNextAttribute;
12084 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12085 break;
12086 case AXIS_CHILD:
12087 last = NULL;
12088 if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
12089 /*
12090 * This iterator will give us only nodes which can
12091 * hold element nodes.
12092 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000012093 outerNext = xmlXPathNextDescendantOrSelfElemParent;
12094 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012095 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12096 (type == NODE_TYPE_NODE))
12097 {
12098 /*
12099 * Optimization if an element node type is 'element'.
12100 */
12101 next = xmlXPathNextChildElement;
12102 } else
12103 next = xmlXPathNextChild;
12104 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12105 break;
12106 case AXIS_DESCENDANT:
12107 last = NULL;
12108 next = xmlXPathNextDescendant;
12109 break;
12110 case AXIS_DESCENDANT_OR_SELF:
12111 last = NULL;
12112 next = xmlXPathNextDescendantOrSelf;
12113 break;
12114 case AXIS_FOLLOWING:
12115 last = NULL;
12116 next = xmlXPathNextFollowing;
12117 break;
12118 case AXIS_FOLLOWING_SIBLING:
12119 last = NULL;
12120 next = xmlXPathNextFollowingSibling;
12121 break;
12122 case AXIS_NAMESPACE:
12123 first = NULL;
12124 last = NULL;
12125 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12126 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12127 break;
12128 case AXIS_PARENT:
12129 first = NULL;
12130 next = xmlXPathNextParent;
12131 break;
12132 case AXIS_PRECEDING:
12133 first = NULL;
12134 next = xmlXPathNextPrecedingInternal;
12135 break;
12136 case AXIS_PRECEDING_SIBLING:
12137 first = NULL;
12138 next = xmlXPathNextPrecedingSibling;
12139 break;
12140 case AXIS_SELF:
12141 first = NULL;
12142 last = NULL;
12143 next = xmlXPathNextSelf;
12144 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12145 break;
12146 }
12147
12148#ifdef DEBUG_STEP
Daniel Veillard074f37e2008-09-01 13:38:22 +000012149 xmlXPathDebugDumpStepAxis(op,
12150 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012151#endif
12152
12153 if (next == NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000012154 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012155 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012156 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012157 contextSeq = obj->nodesetval;
12158 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12159 xmlXPathReleaseObject(xpctxt, obj);
12160 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12161 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012162 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012163 /*
12164 * Predicate optimization ---------------------------------------------
12165 * If this step has a last predicate, which contains a position(),
12166 * then we'll optimize (although not exactly "position()", but only
12167 * the short-hand form, i.e., "[n]".
12168 *
12169 * Example - expression "/foo[parent::bar][1]":
Daniel Veillard45490ae2008-07-29 09:13:19 +000012170 *
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012171 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12172 * ROOT -- op->ch1
12173 * PREDICATE -- op->ch2 (predOp)
12174 * PREDICATE -- predOp->ch1 = [parent::bar]
12175 * SORT
12176 * COLLECT 'parent' 'name' 'node' bar
12177 * NODE
12178 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12179 *
12180 */
12181 maxPos = 0;
12182 predOp = NULL;
12183 hasPredicateRange = 0;
12184 hasAxisRange = 0;
12185 if (op->ch2 != -1) {
12186 /*
12187 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12188 */
12189 predOp = &ctxt->comp->steps[op->ch2];
12190 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12191 if (predOp->ch1 != -1) {
12192 /*
12193 * Use the next inner predicate operator.
12194 */
12195 predOp = &ctxt->comp->steps[predOp->ch1];
12196 hasPredicateRange = 1;
12197 } else {
12198 /*
12199 * There's no other predicate than the [n] predicate.
12200 */
12201 predOp = NULL;
12202 hasAxisRange = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012203 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012204 }
12205 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012206 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012207 /*
12208 * Axis traversal -----------------------------------------------------
12209 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012210 /*
12211 * 2.3 Node Tests
Daniel Veillard45490ae2008-07-29 09:13:19 +000012212 * - For the attribute axis, the principal node type is attribute.
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012213 * - For the namespace axis, the principal node type is namespace.
12214 * - For other axes, the principal node type is element.
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012215 *
12216 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012217 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012218 * select all element children of the context node
12219 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012220 oldContextNode = xpctxt->node;
12221 addNode = xmlXPathNodeSetAddUnique;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012222 outSeq = NULL;
12223 seq = NULL;
12224 outerContextNode = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012225 contextNode = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012226 contextIdx = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012227
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012228
12229 while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
12230 if (outerNext != NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012231 /*
12232 * This is a compound traversal.
12233 */
12234 if (contextNode == NULL) {
12235 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012236 * Set the context for the outer traversal.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012237 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012238 outerContextNode = contextSeq->nodeTab[contextIdx++];
12239 contextNode = outerNext(NULL, outerContextNode);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012240 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012241 contextNode = outerNext(contextNode, outerContextNode);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012242 if (contextNode == NULL)
12243 continue;
12244 /*
12245 * Set the context for the main traversal.
12246 */
12247 xpctxt->node = contextNode;
12248 } else
Daniel Veillard45490ae2008-07-29 09:13:19 +000012249 xpctxt->node = contextSeq->nodeTab[contextIdx++];
12250
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012251 if (seq == NULL) {
12252 seq = xmlXPathNodeSetCreate(NULL);
12253 if (seq == NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012254 total = 0;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012255 goto error;
12256 }
12257 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012258 /*
12259 * Traverse the axis and test the nodes.
12260 */
12261 pos = 0;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012262 cur = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012263 hasNsNodes = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012264 do {
12265 cur = next(ctxt, cur);
12266 if (cur == NULL)
12267 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012268
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012269 /*
12270 * QUESTION TODO: What does the "first" and "last" stuff do?
12271 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012272 if ((first != NULL) && (*first != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012273 if (*first == cur)
12274 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012275 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012276#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012277 (xmlXPathCmpNodesExt(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012278#else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012279 (xmlXPathCmpNodes(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012280#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012281 {
12282 break;
12283 }
12284 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012285 if ((last != NULL) && (*last != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012286 if (*last == cur)
12287 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012288 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012289#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012290 (xmlXPathCmpNodesExt(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012291#else
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012292 (xmlXPathCmpNodes(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012293#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012294 {
12295 break;
12296 }
12297 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012298
12299 total++;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012300
Daniel Veillardf06307e2001-07-03 10:35:50 +000012301#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012302 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12303#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +000012304
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012305 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012306 case NODE_TEST_NONE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012307 total = 0;
12308 STRANGE
12309 goto error;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012310 case NODE_TEST_TYPE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012311 /*
12312 * TODO: Don't we need to use
12313 * xmlXPathNodeSetAddNs() for namespace nodes here?
12314 * Surprisingly, some c14n tests fail, if we do this.
12315 */
12316 if (type == NODE_TYPE_NODE) {
12317 switch (cur->type) {
12318 case XML_DOCUMENT_NODE:
12319 case XML_HTML_DOCUMENT_NODE:
12320#ifdef LIBXML_DOCB_ENABLED
12321 case XML_DOCB_DOCUMENT_NODE:
12322#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +000012323 case XML_ELEMENT_NODE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012324 case XML_ATTRIBUTE_NODE:
12325 case XML_PI_NODE:
12326 case XML_COMMENT_NODE:
12327 case XML_CDATA_SECTION_NODE:
12328 case XML_TEXT_NODE:
12329 case XML_NAMESPACE_DECL:
12330 XP_TEST_HIT
12331 break;
12332 default:
12333 break;
12334 }
12335 } else if (cur->type == type) {
Kasimier T. Buchcik889b7622006-07-03 11:44:13 +000012336 if (type == XML_NAMESPACE_DECL)
12337 XP_TEST_HIT_NS
12338 else
12339 XP_TEST_HIT
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012340 } else if ((type == NODE_TYPE_TEXT) &&
12341 (cur->type == XML_CDATA_SECTION_NODE))
12342 {
12343 XP_TEST_HIT
12344 }
12345 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012346 case NODE_TEST_PI:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012347 if ((cur->type == XML_PI_NODE) &&
12348 ((name == NULL) || xmlStrEqual(name, cur->name)))
12349 {
12350 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012351 }
12352 break;
12353 case NODE_TEST_ALL:
12354 if (axis == AXIS_ATTRIBUTE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012355 if (cur->type == XML_ATTRIBUTE_NODE)
12356 {
12357 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012358 }
12359 } else if (axis == AXIS_NAMESPACE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012360 if (cur->type == XML_NAMESPACE_DECL)
12361 {
12362 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012363 }
12364 } else {
12365 if (cur->type == XML_ELEMENT_NODE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012366 if (prefix == NULL)
12367 {
12368 XP_TEST_HIT
12369
Daniel Veillardf06307e2001-07-03 10:35:50 +000012370 } else if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012371 (xmlStrEqual(URI, cur->ns->href)))
12372 {
12373 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012374 }
12375 }
12376 }
12377 break;
12378 case NODE_TEST_NS:{
12379 TODO;
12380 break;
12381 }
12382 case NODE_TEST_NAME:
Daniel Veillardfe3970e2006-11-23 16:08:30 +000012383 if (axis == AXIS_ATTRIBUTE) {
12384 if (cur->type != XML_ATTRIBUTE_NODE)
12385 break;
12386 } else if (axis == AXIS_NAMESPACE) {
12387 if (cur->type != XML_NAMESPACE_DECL)
12388 break;
12389 } else {
12390 if (cur->type != XML_ELEMENT_NODE)
12391 break;
12392 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012393 switch (cur->type) {
12394 case XML_ELEMENT_NODE:
12395 if (xmlStrEqual(name, cur->name)) {
12396 if (prefix == NULL) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012397 if (cur->ns == NULL)
12398 {
12399 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012400 }
12401 } else {
12402 if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012403 (xmlStrEqual(URI, cur->ns->href)))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012404 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012405 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012406 }
12407 }
12408 }
12409 break;
12410 case XML_ATTRIBUTE_NODE:{
12411 xmlAttrPtr attr = (xmlAttrPtr) cur;
12412
12413 if (xmlStrEqual(name, attr->name)) {
12414 if (prefix == NULL) {
12415 if ((attr->ns == NULL) ||
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012416 (attr->ns->prefix == NULL))
12417 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012418 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012419 }
12420 } else {
12421 if ((attr->ns != NULL) &&
12422 (xmlStrEqual(URI,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012423 attr->ns->href)))
12424 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012425 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012426 }
12427 }
12428 }
12429 break;
12430 }
12431 case XML_NAMESPACE_DECL:
12432 if (cur->type == XML_NAMESPACE_DECL) {
12433 xmlNsPtr ns = (xmlNsPtr) cur;
12434
12435 if ((ns->prefix != NULL) && (name != NULL)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012436 && (xmlStrEqual(ns->prefix, name)))
12437 {
12438 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012439 }
12440 }
12441 break;
12442 default:
12443 break;
12444 }
12445 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012446 } /* switch(test) */
12447 } while (cur != NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012448
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012449 goto apply_predicates;
12450
Daniel Veillard45490ae2008-07-29 09:13:19 +000012451axis_range_end: /* ----------------------------------------------------- */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012452 /*
12453 * We have a "/foo[n]", and position() = n was reached.
12454 * Note that we can have as well "/foo/::parent::foo[1]", so
12455 * a duplicate-aware merge is still needed.
12456 * Merge with the result.
12457 */
12458 if (outSeq == NULL) {
12459 outSeq = seq;
12460 seq = NULL;
12461 } else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012462 outSeq = mergeAndClear(outSeq, seq, 0);
12463 /*
12464 * Break if only a true/false result was requested.
12465 */
12466 if (toBool)
12467 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012468 continue;
12469
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012470first_hit: /* ---------------------------------------------------------- */
12471 /*
12472 * Break if only a true/false result was requested and
12473 * no predicates existed and a node test succeeded.
12474 */
12475 if (outSeq == NULL) {
12476 outSeq = seq;
12477 seq = NULL;
12478 } else
12479 outSeq = mergeAndClear(outSeq, seq, 0);
12480 break;
12481
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012482#ifdef DEBUG_STEP
12483 if (seq != NULL)
12484 nbMatches += seq->nodeNr;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012485#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012486
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012487apply_predicates: /* --------------------------------------------------- */
12488 /*
12489 * Apply predicates.
Daniel Veillard45490ae2008-07-29 09:13:19 +000012490 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012491 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12492 /*
12493 * E.g. when we have a "/foo[some expression][n]".
Daniel Veillard45490ae2008-07-29 09:13:19 +000012494 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012495 /*
12496 * QUESTION TODO: The old predicate evaluation took into
12497 * account location-sets.
12498 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12499 * Do we expect such a set here?
12500 * All what I learned now from the evaluation semantics
12501 * does not indicate that a location-set will be processed
12502 * here, so this looks OK.
Daniel Veillard45490ae2008-07-29 09:13:19 +000012503 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012504 /*
12505 * Iterate over all predicates, starting with the outermost
12506 * predicate.
12507 * TODO: Problem: we cannot execute the inner predicates first
12508 * since we cannot go back *up* the operator tree!
12509 * Options we have:
12510 * 1) Use of recursive functions (like is it currently done
12511 * via xmlXPathCompOpEval())
12512 * 2) Add a predicate evaluation information stack to the
12513 * context struct
12514 * 3) Change the way the operators are linked; we need a
12515 * "parent" field on xmlXPathStepOp
12516 *
12517 * For the moment, I'll try to solve this with a recursive
12518 * function: xmlXPathCompOpEvalPredicate().
Daniel Veillard45490ae2008-07-29 09:13:19 +000012519 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012520 size = seq->nodeNr;
12521 if (hasPredicateRange != 0)
12522 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12523 predOp, seq, size, maxPos, maxPos, hasNsNodes);
12524 else
12525 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12526 predOp, seq, size, hasNsNodes);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012527
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012528 if (ctxt->error != XPATH_EXPRESSION_OK) {
12529 total = 0;
12530 goto error;
12531 }
12532 /*
12533 * Add the filtered set of nodes to the result node set.
12534 */
12535 if (newSize == 0) {
12536 /*
12537 * The predicates filtered all nodes out.
12538 */
12539 xmlXPathNodeSetClear(seq, hasNsNodes);
12540 } else if (seq->nodeNr > 0) {
12541 /*
12542 * Add to result set.
12543 */
12544 if (outSeq == NULL) {
12545 if (size != newSize) {
12546 /*
12547 * We need to merge and clear here, since
12548 * the sequence will contained NULLed entries.
12549 */
12550 outSeq = mergeAndClear(NULL, seq, 1);
12551 } else {
12552 outSeq = seq;
12553 seq = NULL;
12554 }
12555 } else
12556 outSeq = mergeAndClear(outSeq, seq,
12557 (size != newSize) ? 1: 0);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012558 /*
12559 * Break if only a true/false result was requested.
12560 */
12561 if (toBool)
12562 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012563 }
12564 } else if (seq->nodeNr > 0) {
12565 /*
12566 * Add to result set.
12567 */
12568 if (outSeq == NULL) {
12569 outSeq = seq;
12570 seq = NULL;
12571 } else {
12572 outSeq = mergeAndClear(outSeq, seq, 0);
12573 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012574 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012575 }
12576
12577error:
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012578 if ((obj->boolval) && (obj->user != NULL)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012579 /*
12580 * QUESTION TODO: What does this do and why?
12581 * TODO: Do we have to do this also for the "error"
12582 * cleanup further down?
12583 */
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012584 ctxt->value->boolval = 1;
12585 ctxt->value->user = obj->user;
12586 obj->user = NULL;
12587 obj->boolval = 0;
12588 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012589 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012590
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012591 /*
12592 * Ensure we return at least an emtpy set.
12593 */
12594 if (outSeq == NULL) {
12595 if ((seq != NULL) && (seq->nodeNr == 0))
12596 outSeq = seq;
12597 else
12598 outSeq = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +000012599 /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012600 }
12601 if ((seq != NULL) && (seq != outSeq)) {
12602 xmlXPathFreeNodeSet(seq);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012603 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012604 /*
12605 * Hand over the result. Better to push the set also in
12606 * case of errors.
12607 */
12608 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12609 /*
12610 * Reset the context node.
12611 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012612 xpctxt->node = oldContextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012613
12614#ifdef DEBUG_STEP
12615 xmlGenericError(xmlGenericErrorContext,
12616 "\nExamined %d nodes, found %d nodes at that step\n",
12617 total, nbMatches);
12618#endif
12619
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012620 return(total);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012621}
12622
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012623static int
12624xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12625 xmlXPathStepOpPtr op, xmlNodePtr * first);
12626
Daniel Veillardf06307e2001-07-03 10:35:50 +000012627/**
12628 * xmlXPathCompOpEvalFirst:
12629 * @ctxt: the XPath parser context with the compiled expression
12630 * @op: an XPath compiled operation
12631 * @first: the first elem found so far
12632 *
12633 * Evaluate the Precompiled XPath operation searching only the first
12634 * element in document order
12635 *
12636 * Returns the number of examined objects.
12637 */
12638static int
12639xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12640 xmlXPathStepOpPtr op, xmlNodePtr * first)
12641{
12642 int total = 0, cur;
12643 xmlXPathCompExprPtr comp;
12644 xmlXPathObjectPtr arg1, arg2;
12645
Daniel Veillard556c6682001-10-06 09:59:51 +000012646 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012647 comp = ctxt->comp;
12648 switch (op->op) {
12649 case XPATH_OP_END:
12650 return (0);
12651 case XPATH_OP_UNION:
12652 total =
12653 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12654 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012655 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012656 if ((ctxt->value != NULL)
12657 && (ctxt->value->type == XPATH_NODESET)
12658 && (ctxt->value->nodesetval != NULL)
12659 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12660 /*
12661 * limit tree traversing to first node in the result
12662 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012663 /*
12664 * OPTIMIZE TODO: This implicitely sorts
12665 * the result, even if not needed. E.g. if the argument
12666 * of the count() function, no sorting is needed.
12667 * OPTIMIZE TODO: How do we know if the node-list wasn't
12668 * aready sorted?
12669 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012670 if (ctxt->value->nodesetval->nodeNr > 1)
12671 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012672 *first = ctxt->value->nodesetval->nodeTab[0];
12673 }
12674 cur =
12675 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12676 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012677 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012678 CHECK_TYPE0(XPATH_NODESET);
12679 arg2 = valuePop(ctxt);
12680
12681 CHECK_TYPE0(XPATH_NODESET);
12682 arg1 = valuePop(ctxt);
12683
12684 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12685 arg2->nodesetval);
12686 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012687 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012688 /* optimizer */
12689 if (total > cur)
12690 xmlXPathCompSwap(op);
12691 return (total + cur);
12692 case XPATH_OP_ROOT:
12693 xmlXPathRoot(ctxt);
12694 return (0);
12695 case XPATH_OP_NODE:
12696 if (op->ch1 != -1)
12697 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012698 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012699 if (op->ch2 != -1)
12700 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012701 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012702 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12703 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012704 return (total);
12705 case XPATH_OP_RESET:
12706 if (op->ch1 != -1)
12707 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012708 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012709 if (op->ch2 != -1)
12710 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012711 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012712 ctxt->context->node = NULL;
12713 return (total);
12714 case XPATH_OP_COLLECT:{
12715 if (op->ch1 == -1)
12716 return (total);
12717
12718 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012719 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012720
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012721 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012722 return (total);
12723 }
12724 case XPATH_OP_VALUE:
12725 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012726 xmlXPathCacheObjectCopy(ctxt->context,
12727 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012728 return (0);
12729 case XPATH_OP_SORT:
12730 if (op->ch1 != -1)
12731 total +=
12732 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12733 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012734 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012735 if ((ctxt->value != NULL)
12736 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012737 && (ctxt->value->nodesetval != NULL)
12738 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012739 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12740 return (total);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012741#ifdef XP_OPTIMIZED_FILTER_FIRST
12742 case XPATH_OP_FILTER:
Marius Wachtler2ddecc22010-10-12 09:09:07 +020012743 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012744 return (total);
12745#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000012746 default:
12747 return (xmlXPathCompOpEval(ctxt, op));
12748 }
12749}
12750
12751/**
12752 * xmlXPathCompOpEvalLast:
12753 * @ctxt: the XPath parser context with the compiled expression
12754 * @op: an XPath compiled operation
12755 * @last: the last elem found so far
12756 *
12757 * Evaluate the Precompiled XPath operation searching only the last
12758 * element in document order
12759 *
William M. Brack08171912003-12-29 02:52:11 +000012760 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000012761 */
12762static int
12763xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12764 xmlNodePtr * last)
12765{
12766 int total = 0, cur;
12767 xmlXPathCompExprPtr comp;
12768 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +000012769 xmlNodePtr bak;
12770 xmlDocPtr bakd;
12771 int pp;
12772 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012773
Daniel Veillard556c6682001-10-06 09:59:51 +000012774 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012775 comp = ctxt->comp;
12776 switch (op->op) {
12777 case XPATH_OP_END:
12778 return (0);
12779 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +000012780 bakd = ctxt->context->doc;
12781 bak = ctxt->context->node;
12782 pp = ctxt->context->proximityPosition;
12783 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012784 total =
12785 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012786 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012787 if ((ctxt->value != NULL)
12788 && (ctxt->value->type == XPATH_NODESET)
12789 && (ctxt->value->nodesetval != NULL)
12790 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12791 /*
12792 * limit tree traversing to first node in the result
12793 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012794 if (ctxt->value->nodesetval->nodeNr > 1)
12795 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012796 *last =
12797 ctxt->value->nodesetval->nodeTab[ctxt->value->
12798 nodesetval->nodeNr -
12799 1];
12800 }
William M. Brackce4fc562004-01-22 02:47:18 +000012801 ctxt->context->doc = bakd;
12802 ctxt->context->node = bak;
12803 ctxt->context->proximityPosition = pp;
12804 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012805 cur =
12806 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012807 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012808 if ((ctxt->value != NULL)
12809 && (ctxt->value->type == XPATH_NODESET)
12810 && (ctxt->value->nodesetval != NULL)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012811 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012812 }
12813 CHECK_TYPE0(XPATH_NODESET);
12814 arg2 = valuePop(ctxt);
12815
12816 CHECK_TYPE0(XPATH_NODESET);
12817 arg1 = valuePop(ctxt);
12818
12819 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12820 arg2->nodesetval);
12821 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012822 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012823 /* optimizer */
12824 if (total > cur)
12825 xmlXPathCompSwap(op);
12826 return (total + cur);
12827 case XPATH_OP_ROOT:
12828 xmlXPathRoot(ctxt);
12829 return (0);
12830 case XPATH_OP_NODE:
12831 if (op->ch1 != -1)
12832 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012833 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012834 if (op->ch2 != -1)
12835 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012836 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012837 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12838 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012839 return (total);
12840 case XPATH_OP_RESET:
12841 if (op->ch1 != -1)
12842 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012843 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012844 if (op->ch2 != -1)
12845 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012846 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012847 ctxt->context->node = NULL;
12848 return (total);
12849 case XPATH_OP_COLLECT:{
12850 if (op->ch1 == -1)
12851 return (0);
12852
12853 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012854 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012855
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012856 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012857 return (total);
12858 }
12859 case XPATH_OP_VALUE:
12860 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012861 xmlXPathCacheObjectCopy(ctxt->context,
12862 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012863 return (0);
12864 case XPATH_OP_SORT:
12865 if (op->ch1 != -1)
12866 total +=
12867 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12868 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012869 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012870 if ((ctxt->value != NULL)
12871 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012872 && (ctxt->value->nodesetval != NULL)
12873 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012874 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12875 return (total);
12876 default:
12877 return (xmlXPathCompOpEval(ctxt, op));
12878 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012879}
12880
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012881#ifdef XP_OPTIMIZED_FILTER_FIRST
12882static int
12883xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12884 xmlXPathStepOpPtr op, xmlNodePtr * first)
12885{
12886 int total = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012887 xmlXPathCompExprPtr comp;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012888 xmlXPathObjectPtr res;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012889 xmlXPathObjectPtr obj;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012890 xmlNodeSetPtr oldset;
12891 xmlNodePtr oldnode;
12892 xmlDocPtr oldDoc;
12893 int i;
12894
12895 CHECK_ERROR0;
12896 comp = ctxt->comp;
12897 /*
12898 * Optimization for ()[last()] selection i.e. the last elem
12899 */
12900 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12901 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12902 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12903 int f = comp->steps[op->ch2].ch1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012904
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012905 if ((f != -1) &&
12906 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12907 (comp->steps[f].value5 == NULL) &&
12908 (comp->steps[f].value == 0) &&
12909 (comp->steps[f].value4 != NULL) &&
12910 (xmlStrEqual
12911 (comp->steps[f].value4, BAD_CAST "last"))) {
12912 xmlNodePtr last = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012913
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012914 total +=
12915 xmlXPathCompOpEvalLast(ctxt,
12916 &comp->steps[op->ch1],
12917 &last);
12918 CHECK_ERROR0;
12919 /*
12920 * The nodeset should be in document order,
12921 * Keep only the last value
12922 */
12923 if ((ctxt->value != NULL) &&
12924 (ctxt->value->type == XPATH_NODESET) &&
12925 (ctxt->value->nodesetval != NULL) &&
12926 (ctxt->value->nodesetval->nodeTab != NULL) &&
12927 (ctxt->value->nodesetval->nodeNr > 1)) {
12928 ctxt->value->nodesetval->nodeTab[0] =
12929 ctxt->value->nodesetval->nodeTab[ctxt->
12930 value->
12931 nodesetval->
12932 nodeNr -
12933 1];
12934 ctxt->value->nodesetval->nodeNr = 1;
12935 *first = *(ctxt->value->nodesetval->nodeTab);
12936 }
12937 return (total);
12938 }
12939 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012940
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012941 if (op->ch1 != -1)
12942 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12943 CHECK_ERROR0;
12944 if (op->ch2 == -1)
12945 return (total);
12946 if (ctxt->value == NULL)
12947 return (total);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012948
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012949#ifdef LIBXML_XPTR_ENABLED
12950 oldnode = ctxt->context->node;
12951 /*
12952 * Hum are we filtering the result of an XPointer expression
12953 */
12954 if (ctxt->value->type == XPATH_LOCATIONSET) {
12955 xmlXPathObjectPtr tmp = NULL;
12956 xmlLocationSetPtr newlocset = NULL;
12957 xmlLocationSetPtr oldlocset;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012958
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012959 /*
12960 * Extract the old locset, and then evaluate the result of the
12961 * expression for all the element in the locset. use it to grow
12962 * up a new locset.
12963 */
12964 CHECK_TYPE0(XPATH_LOCATIONSET);
12965 obj = valuePop(ctxt);
12966 oldlocset = obj->user;
12967 ctxt->context->node = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012968
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012969 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12970 ctxt->context->contextSize = 0;
12971 ctxt->context->proximityPosition = 0;
12972 if (op->ch2 != -1)
12973 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12974 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012975 if (res != NULL) {
12976 xmlXPathReleaseObject(ctxt->context, res);
12977 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012978 valuePush(ctxt, obj);
12979 CHECK_ERROR0;
12980 return (total);
12981 }
12982 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012983
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012984 for (i = 0; i < oldlocset->locNr; i++) {
12985 /*
12986 * Run the evaluation with a node list made of a
12987 * single item in the nodelocset.
12988 */
12989 ctxt->context->node = oldlocset->locTab[i]->user;
12990 ctxt->context->contextSize = oldlocset->locNr;
12991 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012992 if (tmp == NULL) {
12993 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12994 ctxt->context->node);
12995 } else {
12996 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12997 ctxt->context->node);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012998 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012999 valuePush(ctxt, tmp);
13000 if (op->ch2 != -1)
13001 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13002 if (ctxt->error != XPATH_EXPRESSION_OK) {
13003 xmlXPathFreeObject(obj);
13004 return(0);
13005 }
13006 /*
13007 * The result of the evaluation need to be tested to
13008 * decided whether the filter succeeded or not
13009 */
13010 res = valuePop(ctxt);
13011 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13012 xmlXPtrLocationSetAdd(newlocset,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013013 xmlXPathCacheObjectCopy(ctxt->context,
13014 oldlocset->locTab[i]));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013015 }
13016 /*
13017 * Cleanup
13018 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013019 if (res != NULL) {
13020 xmlXPathReleaseObject(ctxt->context, res);
13021 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013022 if (ctxt->value == tmp) {
13023 valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013024 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013025 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013026 * REVISIT TODO: Don't create a temporary nodeset
13027 * for everly iteration.
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013028 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013029 /* OLD: xmlXPathFreeObject(res); */
13030 } else
Daniel Veillard45490ae2008-07-29 09:13:19 +000013031 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013032 ctxt->context->node = NULL;
13033 /*
13034 * Only put the first node in the result, then leave.
13035 */
13036 if (newlocset->locNr > 0) {
13037 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
13038 break;
13039 }
13040 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013041 if (tmp != NULL) {
13042 xmlXPathReleaseObject(ctxt->context, tmp);
13043 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013044 /*
13045 * The result is used as the new evaluation locset.
13046 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013047 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013048 ctxt->context->node = NULL;
13049 ctxt->context->contextSize = -1;
13050 ctxt->context->proximityPosition = -1;
13051 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13052 ctxt->context->node = oldnode;
13053 return (total);
13054 }
13055#endif /* LIBXML_XPTR_ENABLED */
Daniel Veillard45490ae2008-07-29 09:13:19 +000013056
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013057 /*
13058 * Extract the old set, and then evaluate the result of the
13059 * expression for all the element in the set. use it to grow
13060 * up a new set.
13061 */
13062 CHECK_TYPE0(XPATH_NODESET);
13063 obj = valuePop(ctxt);
13064 oldset = obj->nodesetval;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013065
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013066 oldnode = ctxt->context->node;
13067 oldDoc = ctxt->context->doc;
13068 ctxt->context->node = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013069
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013070 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13071 ctxt->context->contextSize = 0;
13072 ctxt->context->proximityPosition = 0;
13073 /* QUESTION TODO: Why was this code commented out?
13074 if (op->ch2 != -1)
13075 total +=
13076 xmlXPathCompOpEval(ctxt,
13077 &comp->steps[op->ch2]);
13078 CHECK_ERROR0;
13079 res = valuePop(ctxt);
13080 if (res != NULL)
13081 xmlXPathFreeObject(res);
13082 */
13083 valuePush(ctxt, obj);
13084 ctxt->context->node = oldnode;
13085 CHECK_ERROR0;
13086 } else {
13087 xmlNodeSetPtr newset;
13088 xmlXPathObjectPtr tmp = NULL;
13089 /*
13090 * Initialize the new set.
13091 * Also set the xpath document in case things like
13092 * key() evaluation are attempted on the predicate
Daniel Veillard45490ae2008-07-29 09:13:19 +000013093 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013094 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +000013095 /* XXX what if xmlXPathNodeSetCreate returned NULL? */
Daniel Veillard45490ae2008-07-29 09:13:19 +000013096
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013097 for (i = 0; i < oldset->nodeNr; i++) {
13098 /*
13099 * Run the evaluation with a node list made of
13100 * a single item in the nodeset.
13101 */
13102 ctxt->context->node = oldset->nodeTab[i];
13103 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13104 (oldset->nodeTab[i]->doc != NULL))
13105 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013106 if (tmp == NULL) {
13107 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13108 ctxt->context->node);
13109 } else {
13110 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13111 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013112 }
13113 valuePush(ctxt, tmp);
13114 ctxt->context->contextSize = oldset->nodeNr;
13115 ctxt->context->proximityPosition = i + 1;
13116 if (op->ch2 != -1)
13117 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13118 if (ctxt->error != XPATH_EXPRESSION_OK) {
13119 xmlXPathFreeNodeSet(newset);
13120 xmlXPathFreeObject(obj);
13121 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013122 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013123 /*
13124 * The result of the evaluation needs to be tested to
13125 * decide whether the filter succeeded or not
13126 */
13127 res = valuePop(ctxt);
13128 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13129 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013130 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013131 /*
13132 * Cleanup
13133 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013134 if (res != NULL) {
13135 xmlXPathReleaseObject(ctxt->context, res);
13136 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013137 if (ctxt->value == tmp) {
13138 valuePop(ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013139 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013140 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013141 * in order to avoid massive recreation inside this
13142 * loop.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013143 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000013144 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013145 } else
13146 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013147 ctxt->context->node = NULL;
13148 /*
13149 * Only put the first node in the result, then leave.
13150 */
13151 if (newset->nodeNr > 0) {
13152 *first = *(newset->nodeTab);
13153 break;
13154 }
13155 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013156 if (tmp != NULL) {
13157 xmlXPathReleaseObject(ctxt->context, tmp);
13158 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013159 /*
13160 * The result is used as the new evaluation set.
13161 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013162 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013163 ctxt->context->node = NULL;
13164 ctxt->context->contextSize = -1;
13165 ctxt->context->proximityPosition = -1;
13166 /* may want to move this past the '}' later */
13167 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013168 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013169 }
13170 ctxt->context->node = oldnode;
13171 return(total);
13172}
13173#endif /* XP_OPTIMIZED_FILTER_FIRST */
13174
Owen Taylor3473f882001-02-23 17:55:21 +000013175/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013176 * xmlXPathCompOpEval:
13177 * @ctxt: the XPath parser context with the compiled expression
13178 * @op: an XPath compiled operation
13179 *
13180 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000013181 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013182 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013183static int
13184xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13185{
13186 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013187 int equal, ret;
13188 xmlXPathCompExprPtr comp;
13189 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013190 xmlNodePtr bak;
13191 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000013192 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000013193 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013194
Daniel Veillard556c6682001-10-06 09:59:51 +000013195 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013196 comp = ctxt->comp;
13197 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013198 case XPATH_OP_END:
13199 return (0);
13200 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013201 bakd = ctxt->context->doc;
13202 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013203 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013204 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013205 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013206 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013207 xmlXPathBooleanFunction(ctxt, 1);
13208 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13209 return (total);
13210 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013211 ctxt->context->doc = bakd;
13212 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013213 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013214 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013215 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013216 if (ctxt->error) {
13217 xmlXPathFreeObject(arg2);
13218 return(0);
13219 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013220 xmlXPathBooleanFunction(ctxt, 1);
13221 arg1 = valuePop(ctxt);
13222 arg1->boolval &= arg2->boolval;
13223 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013224 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013225 return (total);
13226 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013227 bakd = ctxt->context->doc;
13228 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013229 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013230 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013231 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013232 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013233 xmlXPathBooleanFunction(ctxt, 1);
13234 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13235 return (total);
13236 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013237 ctxt->context->doc = bakd;
13238 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013239 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013240 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013241 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013242 if (ctxt->error) {
13243 xmlXPathFreeObject(arg2);
13244 return(0);
13245 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013246 xmlXPathBooleanFunction(ctxt, 1);
13247 arg1 = valuePop(ctxt);
13248 arg1->boolval |= arg2->boolval;
13249 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013250 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013251 return (total);
13252 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013253 bakd = ctxt->context->doc;
13254 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013255 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013256 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013257 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013258 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013259 ctxt->context->doc = bakd;
13260 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013261 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013262 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013263 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013264 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000013265 if (op->value)
Daniel Veillard45490ae2008-07-29 09:13:19 +000013266 equal = xmlXPathEqualValues(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +000013267 else
13268 equal = xmlXPathNotEqualValues(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013269 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013270 return (total);
13271 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013272 bakd = ctxt->context->doc;
13273 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013274 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013275 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013276 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013277 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013278 ctxt->context->doc = bakd;
13279 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013280 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013281 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013282 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013283 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013284 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013285 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013286 return (total);
13287 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013288 bakd = ctxt->context->doc;
13289 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013290 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013291 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013292 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013293 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013294 if (op->ch2 != -1) {
13295 ctxt->context->doc = bakd;
13296 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013297 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013298 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013299 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013300 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013301 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013302 if (op->value == 0)
13303 xmlXPathSubValues(ctxt);
13304 else if (op->value == 1)
13305 xmlXPathAddValues(ctxt);
13306 else if (op->value == 2)
13307 xmlXPathValueFlipSign(ctxt);
13308 else if (op->value == 3) {
13309 CAST_TO_NUMBER;
13310 CHECK_TYPE0(XPATH_NUMBER);
13311 }
13312 return (total);
13313 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013314 bakd = ctxt->context->doc;
13315 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013316 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013317 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013318 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013319 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013320 ctxt->context->doc = bakd;
13321 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013322 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013323 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013324 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013325 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013326 if (op->value == 0)
13327 xmlXPathMultValues(ctxt);
13328 else if (op->value == 1)
13329 xmlXPathDivValues(ctxt);
13330 else if (op->value == 2)
13331 xmlXPathModValues(ctxt);
13332 return (total);
13333 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013334 bakd = ctxt->context->doc;
13335 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013336 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013337 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013338 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013339 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013340 ctxt->context->doc = bakd;
13341 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013342 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013343 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013344 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013345 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013346 CHECK_TYPE0(XPATH_NODESET);
13347 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013348
Daniel Veillardf06307e2001-07-03 10:35:50 +000013349 CHECK_TYPE0(XPATH_NODESET);
13350 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013351
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013352 if ((arg1->nodesetval == NULL) ||
13353 ((arg2->nodesetval != NULL) &&
13354 (arg2->nodesetval->nodeNr != 0)))
13355 {
13356 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13357 arg2->nodesetval);
13358 }
13359
Daniel Veillardf06307e2001-07-03 10:35:50 +000013360 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013361 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013362 return (total);
13363 case XPATH_OP_ROOT:
13364 xmlXPathRoot(ctxt);
13365 return (total);
13366 case XPATH_OP_NODE:
13367 if (op->ch1 != -1)
13368 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013369 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013370 if (op->ch2 != -1)
13371 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013372 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013373 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13374 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013375 return (total);
13376 case XPATH_OP_RESET:
13377 if (op->ch1 != -1)
13378 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013379 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013380 if (op->ch2 != -1)
13381 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013382 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013383 ctxt->context->node = NULL;
13384 return (total);
13385 case XPATH_OP_COLLECT:{
13386 if (op->ch1 == -1)
13387 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000013388
Daniel Veillardf06307e2001-07-03 10:35:50 +000013389 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013390 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013391
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013392 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013393 return (total);
13394 }
13395 case XPATH_OP_VALUE:
13396 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013397 xmlXPathCacheObjectCopy(ctxt->context,
13398 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013399 return (total);
13400 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000013401 xmlXPathObjectPtr val;
13402
Daniel Veillardf06307e2001-07-03 10:35:50 +000013403 if (op->ch1 != -1)
13404 total +=
13405 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013406 if (op->value5 == NULL) {
13407 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13408 if (val == NULL) {
13409 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13410 return(0);
13411 }
13412 valuePush(ctxt, val);
13413 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013414 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013415
Daniel Veillardf06307e2001-07-03 10:35:50 +000013416 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13417 if (URI == NULL) {
13418 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013419 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13420 (char *) op->value4, (char *)op->value5);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080013421 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013422 return (total);
13423 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013424 val = xmlXPathVariableLookupNS(ctxt->context,
13425 op->value4, URI);
13426 if (val == NULL) {
13427 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13428 return(0);
13429 }
13430 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013431 }
13432 return (total);
13433 }
13434 case XPATH_OP_FUNCTION:{
13435 xmlXPathFunction func;
13436 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000013437 int i;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013438 int frame;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013439
Daniel Veillardf5048b32011-08-18 17:10:13 +080013440 frame = xmlXPathSetFrame(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013441 if (op->ch1 != -1)
13442 total +=
13443 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013444 if (ctxt->valueNr < op->value) {
13445 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013446 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013447 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013448 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard556c6682001-10-06 09:59:51 +000013449 return (total);
13450 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080013451 for (i = 0; i < op->value; i++) {
Daniel Veillard556c6682001-10-06 09:59:51 +000013452 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13453 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013454 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013455 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013456 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard556c6682001-10-06 09:59:51 +000013457 return (total);
13458 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080013459 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013460 if (op->cache != NULL)
William M. Brackad0e67c2004-12-01 14:35:10 +000013461 XML_CAST_FPTR(func) = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013462 else {
13463 const xmlChar *URI = NULL;
13464
13465 if (op->value5 == NULL)
13466 func =
13467 xmlXPathFunctionLookup(ctxt->context,
13468 op->value4);
13469 else {
13470 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13471 if (URI == NULL) {
13472 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013473 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13474 (char *)op->value4, (char *)op->value5);
Daniel Veillardf5048b32011-08-18 17:10:13 +080013475 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080013476 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013477 return (total);
13478 }
13479 func = xmlXPathFunctionLookupNS(ctxt->context,
13480 op->value4, URI);
13481 }
13482 if (func == NULL) {
13483 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013484 "xmlXPathCompOpEval: function %s not found\n",
13485 (char *)op->value4);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013486 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013487 }
William M. Brackad0e67c2004-12-01 14:35:10 +000013488 op->cache = XML_CAST_FPTR(func);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013489 op->cacheURI = (void *) URI;
13490 }
13491 oldFunc = ctxt->context->function;
13492 oldFuncURI = ctxt->context->functionURI;
13493 ctxt->context->function = op->value4;
13494 ctxt->context->functionURI = op->cacheURI;
13495 func(ctxt, op->value);
13496 ctxt->context->function = oldFunc;
13497 ctxt->context->functionURI = oldFuncURI;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013498 xmlXPathPopFrame(ctxt, frame);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013499 return (total);
13500 }
13501 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000013502 bakd = ctxt->context->doc;
13503 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000013504 pp = ctxt->context->proximityPosition;
13505 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013506 if (op->ch1 != -1)
13507 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
William M. Brack645a9242004-11-09 12:20:42 +000013508 ctxt->context->contextSize = cs;
13509 ctxt->context->proximityPosition = pp;
Daniel Veillard088bf112002-05-14 11:03:59 +000013510 ctxt->context->node = bak;
William M. Brack645a9242004-11-09 12:20:42 +000013511 ctxt->context->doc = bakd;
Daniel Veillard556c6682001-10-06 09:59:51 +000013512 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000013513 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013514 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000013515 ctxt->context->doc = bakd;
13516 ctxt->context->node = bak;
13517 CHECK_ERROR0;
13518 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013519 return (total);
13520 case XPATH_OP_PREDICATE:
13521 case XPATH_OP_FILTER:{
13522 xmlXPathObjectPtr res;
13523 xmlXPathObjectPtr obj, tmp;
13524 xmlNodeSetPtr newset = NULL;
13525 xmlNodeSetPtr oldset;
13526 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000013527 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013528 int i;
13529
13530 /*
13531 * Optimization for ()[1] selection i.e. the first elem
13532 */
13533 if ((op->ch1 != -1) && (op->ch2 != -1) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013534#ifdef XP_OPTIMIZED_FILTER_FIRST
13535 /*
13536 * FILTER TODO: Can we assume that the inner processing
13537 * will result in an ordered list if we have an
13538 * XPATH_OP_FILTER?
13539 * What about an additional field or flag on
13540 * xmlXPathObject like @sorted ? This way we wouln'd need
13541 * to assume anything, so it would be more robust and
13542 * easier to optimize.
13543 */
13544 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13545 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13546#else
13547 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13548#endif
13549 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013550 xmlXPathObjectPtr val;
13551
13552 val = comp->steps[op->ch2].value4;
13553 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13554 (val->floatval == 1.0)) {
13555 xmlNodePtr first = NULL;
13556
13557 total +=
13558 xmlXPathCompOpEvalFirst(ctxt,
13559 &comp->steps[op->ch1],
13560 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000013561 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013562 /*
13563 * The nodeset should be in document order,
13564 * Keep only the first value
13565 */
13566 if ((ctxt->value != NULL) &&
13567 (ctxt->value->type == XPATH_NODESET) &&
13568 (ctxt->value->nodesetval != NULL) &&
13569 (ctxt->value->nodesetval->nodeNr > 1))
13570 ctxt->value->nodesetval->nodeNr = 1;
13571 return (total);
13572 }
13573 }
13574 /*
13575 * Optimization for ()[last()] selection i.e. the last elem
13576 */
13577 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13578 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13579 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13580 int f = comp->steps[op->ch2].ch1;
13581
13582 if ((f != -1) &&
13583 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13584 (comp->steps[f].value5 == NULL) &&
13585 (comp->steps[f].value == 0) &&
13586 (comp->steps[f].value4 != NULL) &&
13587 (xmlStrEqual
13588 (comp->steps[f].value4, BAD_CAST "last"))) {
13589 xmlNodePtr last = NULL;
13590
13591 total +=
13592 xmlXPathCompOpEvalLast(ctxt,
13593 &comp->steps[op->ch1],
13594 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000013595 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013596 /*
13597 * The nodeset should be in document order,
13598 * Keep only the last value
13599 */
13600 if ((ctxt->value != NULL) &&
13601 (ctxt->value->type == XPATH_NODESET) &&
13602 (ctxt->value->nodesetval != NULL) &&
13603 (ctxt->value->nodesetval->nodeTab != NULL) &&
13604 (ctxt->value->nodesetval->nodeNr > 1)) {
13605 ctxt->value->nodesetval->nodeTab[0] =
13606 ctxt->value->nodesetval->nodeTab[ctxt->
13607 value->
13608 nodesetval->
13609 nodeNr -
13610 1];
13611 ctxt->value->nodesetval->nodeNr = 1;
13612 }
13613 return (total);
13614 }
13615 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013616 /*
13617 * Process inner predicates first.
13618 * Example "index[parent::book][1]":
13619 * ...
13620 * PREDICATE <-- we are here "[1]"
13621 * PREDICATE <-- process "[parent::book]" first
13622 * SORT
13623 * COLLECT 'parent' 'name' 'node' book
13624 * NODE
13625 * ELEM Object is a number : 1
13626 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013627 if (op->ch1 != -1)
13628 total +=
13629 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013630 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013631 if (op->ch2 == -1)
13632 return (total);
13633 if (ctxt->value == NULL)
13634 return (total);
13635
13636 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013637
13638#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013639 /*
13640 * Hum are we filtering the result of an XPointer expression
13641 */
13642 if (ctxt->value->type == XPATH_LOCATIONSET) {
13643 xmlLocationSetPtr newlocset = NULL;
13644 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013645
Daniel Veillardf06307e2001-07-03 10:35:50 +000013646 /*
13647 * Extract the old locset, and then evaluate the result of the
13648 * expression for all the element in the locset. use it to grow
13649 * up a new locset.
13650 */
13651 CHECK_TYPE0(XPATH_LOCATIONSET);
13652 obj = valuePop(ctxt);
13653 oldlocset = obj->user;
13654 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013655
Daniel Veillardf06307e2001-07-03 10:35:50 +000013656 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13657 ctxt->context->contextSize = 0;
13658 ctxt->context->proximityPosition = 0;
13659 if (op->ch2 != -1)
13660 total +=
13661 xmlXPathCompOpEval(ctxt,
13662 &comp->steps[op->ch2]);
13663 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013664 if (res != NULL) {
13665 xmlXPathReleaseObject(ctxt->context, res);
13666 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013667 valuePush(ctxt, obj);
13668 CHECK_ERROR0;
13669 return (total);
13670 }
13671 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013672
Daniel Veillardf06307e2001-07-03 10:35:50 +000013673 for (i = 0; i < oldlocset->locNr; i++) {
13674 /*
13675 * Run the evaluation with a node list made of a
13676 * single item in the nodelocset.
13677 */
13678 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013679 ctxt->context->contextSize = oldlocset->locNr;
13680 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013681 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13682 ctxt->context->node);
William M. Brackf7eb7942003-12-31 07:59:17 +000013683 valuePush(ctxt, tmp);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013684
Daniel Veillardf06307e2001-07-03 10:35:50 +000013685 if (op->ch2 != -1)
13686 total +=
13687 xmlXPathCompOpEval(ctxt,
13688 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013689 if (ctxt->error != XPATH_EXPRESSION_OK) {
13690 xmlXPathFreeObject(obj);
13691 return(0);
13692 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013693
Daniel Veillardf06307e2001-07-03 10:35:50 +000013694 /*
13695 * The result of the evaluation need to be tested to
13696 * decided whether the filter succeeded or not
13697 */
13698 res = valuePop(ctxt);
13699 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13700 xmlXPtrLocationSetAdd(newlocset,
13701 xmlXPathObjectCopy
13702 (oldlocset->locTab[i]));
13703 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013704
Daniel Veillardf06307e2001-07-03 10:35:50 +000013705 /*
13706 * Cleanup
13707 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013708 if (res != NULL) {
13709 xmlXPathReleaseObject(ctxt->context, res);
13710 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013711 if (ctxt->value == tmp) {
13712 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013713 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013714 }
13715
13716 ctxt->context->node = NULL;
13717 }
13718
13719 /*
13720 * The result is used as the new evaluation locset.
13721 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013722 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013723 ctxt->context->node = NULL;
13724 ctxt->context->contextSize = -1;
13725 ctxt->context->proximityPosition = -1;
13726 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13727 ctxt->context->node = oldnode;
13728 return (total);
13729 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013730#endif /* LIBXML_XPTR_ENABLED */
13731
Daniel Veillardf06307e2001-07-03 10:35:50 +000013732 /*
13733 * Extract the old set, and then evaluate the result of the
13734 * expression for all the element in the set. use it to grow
13735 * up a new set.
13736 */
13737 CHECK_TYPE0(XPATH_NODESET);
13738 obj = valuePop(ctxt);
13739 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000013740
Daniel Veillardf06307e2001-07-03 10:35:50 +000013741 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000013742 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013743 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013744
Daniel Veillardf06307e2001-07-03 10:35:50 +000013745 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13746 ctxt->context->contextSize = 0;
13747 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000013748/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000013749 if (op->ch2 != -1)
13750 total +=
13751 xmlXPathCompOpEval(ctxt,
13752 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013753 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013754 res = valuePop(ctxt);
13755 if (res != NULL)
13756 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000013757*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000013758 valuePush(ctxt, obj);
13759 ctxt->context->node = oldnode;
13760 CHECK_ERROR0;
13761 } else {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013762 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013763 /*
13764 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000013765 * Also set the xpath document in case things like
13766 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000013767 */
13768 newset = xmlXPathNodeSetCreate(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013769 /*
13770 * SPEC XPath 1.0:
13771 * "For each node in the node-set to be filtered, the
13772 * PredicateExpr is evaluated with that node as the
13773 * context node, with the number of nodes in the
13774 * node-set as the context size, and with the proximity
13775 * position of the node in the node-set with respect to
13776 * the axis as the context position;"
13777 * @oldset is the node-set" to be filtered.
13778 *
13779 * SPEC XPath 1.0:
13780 * "only predicates change the context position and
13781 * context size (see [2.4 Predicates])."
13782 * Example:
13783 * node-set context pos
13784 * nA 1
13785 * nB 2
13786 * nC 3
13787 * After applying predicate [position() > 1] :
13788 * node-set context pos
13789 * nB 1
13790 * nC 2
13791 *
13792 * removed the first node in the node-set, then
Daniel Veillard45490ae2008-07-29 09:13:19 +000013793 * the context position of the
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013794 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013795 for (i = 0; i < oldset->nodeNr; i++) {
13796 /*
13797 * Run the evaluation with a node list made of
13798 * a single item in the nodeset.
13799 */
13800 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000013801 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13802 (oldset->nodeTab[i]->doc != NULL))
13803 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013804 if (tmp == NULL) {
13805 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13806 ctxt->context->node);
13807 } else {
13808 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13809 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013810 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013811 valuePush(ctxt, tmp);
13812 ctxt->context->contextSize = oldset->nodeNr;
13813 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013814 /*
13815 * Evaluate the predicate against the context node.
13816 * Can/should we optimize position() predicates
13817 * here (e.g. "[1]")?
13818 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013819 if (op->ch2 != -1)
13820 total +=
13821 xmlXPathCompOpEval(ctxt,
13822 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013823 if (ctxt->error != XPATH_EXPRESSION_OK) {
13824 xmlXPathFreeNodeSet(newset);
13825 xmlXPathFreeObject(obj);
13826 return(0);
13827 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013828
Daniel Veillardf06307e2001-07-03 10:35:50 +000013829 /*
William M. Brack08171912003-12-29 02:52:11 +000013830 * The result of the evaluation needs to be tested to
13831 * decide whether the filter succeeded or not
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013832 */
13833 /*
13834 * OPTIMIZE TODO: Can we use
13835 * xmlXPathNodeSetAdd*Unique()* instead?
13836 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013837 res = valuePop(ctxt);
13838 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13839 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13840 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013841
Daniel Veillardf06307e2001-07-03 10:35:50 +000013842 /*
13843 * Cleanup
13844 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013845 if (res != NULL) {
13846 xmlXPathReleaseObject(ctxt->context, res);
13847 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013848 if (ctxt->value == tmp) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013849 valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013850 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013851 /*
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013852 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013853 * in order to avoid massive recreation inside this
13854 * loop.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013855 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013856 } else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013857 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013858 ctxt->context->node = NULL;
13859 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013860 if (tmp != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013861 xmlXPathReleaseObject(ctxt->context, tmp);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013862 /*
13863 * The result is used as the new evaluation set.
13864 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013865 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013866 ctxt->context->node = NULL;
13867 ctxt->context->contextSize = -1;
13868 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000013869 /* may want to move this past the '}' later */
13870 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013871 valuePush(ctxt,
13872 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013873 }
13874 ctxt->context->node = oldnode;
13875 return (total);
13876 }
13877 case XPATH_OP_SORT:
13878 if (op->ch1 != -1)
13879 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013880 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013881 if ((ctxt->value != NULL) &&
13882 (ctxt->value->type == XPATH_NODESET) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013883 (ctxt->value->nodesetval != NULL) &&
13884 (ctxt->value->nodesetval->nodeNr > 1))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013885 {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013886 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013887 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013888 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013889#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013890 case XPATH_OP_RANGETO:{
13891 xmlXPathObjectPtr range;
13892 xmlXPathObjectPtr res, obj;
13893 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000013894 xmlLocationSetPtr newlocset = NULL;
13895 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013896 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000013897 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013898
Daniel Veillardf06307e2001-07-03 10:35:50 +000013899 if (op->ch1 != -1)
13900 total +=
13901 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13902 if (op->ch2 == -1)
13903 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013904
William M. Brack08171912003-12-29 02:52:11 +000013905 if (ctxt->value->type == XPATH_LOCATIONSET) {
13906 /*
13907 * Extract the old locset, and then evaluate the result of the
13908 * expression for all the element in the locset. use it to grow
13909 * up a new locset.
13910 */
13911 CHECK_TYPE0(XPATH_LOCATIONSET);
13912 obj = valuePop(ctxt);
13913 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013914
William M. Brack08171912003-12-29 02:52:11 +000013915 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000013916 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000013917 ctxt->context->contextSize = 0;
13918 ctxt->context->proximityPosition = 0;
13919 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13920 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013921 if (res != NULL) {
13922 xmlXPathReleaseObject(ctxt->context, res);
13923 }
William M. Brack08171912003-12-29 02:52:11 +000013924 valuePush(ctxt, obj);
13925 CHECK_ERROR0;
13926 return (total);
13927 }
13928 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013929
William M. Brack08171912003-12-29 02:52:11 +000013930 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013931 /*
William M. Brack08171912003-12-29 02:52:11 +000013932 * Run the evaluation with a node list made of a
13933 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000013934 */
William M. Brackf7eb7942003-12-31 07:59:17 +000013935 ctxt->context->node = oldlocset->locTab[i]->user;
13936 ctxt->context->contextSize = oldlocset->locNr;
13937 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013938 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13939 ctxt->context->node);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013940 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013941
Daniel Veillardf06307e2001-07-03 10:35:50 +000013942 if (op->ch2 != -1)
13943 total +=
13944 xmlXPathCompOpEval(ctxt,
13945 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013946 if (ctxt->error != XPATH_EXPRESSION_OK) {
13947 xmlXPathFreeObject(obj);
13948 return(0);
13949 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013950
Daniel Veillardf06307e2001-07-03 10:35:50 +000013951 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000013952 if (res->type == XPATH_LOCATIONSET) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000013953 xmlLocationSetPtr rloc =
William M. Brack72ee48d2003-12-30 08:30:19 +000013954 (xmlLocationSetPtr)res->user;
13955 for (j=0; j<rloc->locNr; j++) {
13956 range = xmlXPtrNewRange(
13957 oldlocset->locTab[i]->user,
13958 oldlocset->locTab[i]->index,
13959 rloc->locTab[j]->user2,
13960 rloc->locTab[j]->index2);
13961 if (range != NULL) {
13962 xmlXPtrLocationSetAdd(newlocset, range);
13963 }
13964 }
13965 } else {
13966 range = xmlXPtrNewRangeNodeObject(
13967 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13968 if (range != NULL) {
13969 xmlXPtrLocationSetAdd(newlocset,range);
13970 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013971 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013972
Daniel Veillardf06307e2001-07-03 10:35:50 +000013973 /*
13974 * Cleanup
13975 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013976 if (res != NULL) {
13977 xmlXPathReleaseObject(ctxt->context, res);
13978 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013979 if (ctxt->value == tmp) {
13980 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013981 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013982 }
13983
13984 ctxt->context->node = NULL;
13985 }
William M. Brack72ee48d2003-12-30 08:30:19 +000013986 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000013987 CHECK_TYPE0(XPATH_NODESET);
13988 obj = valuePop(ctxt);
13989 oldset = obj->nodesetval;
13990 ctxt->context->node = NULL;
13991
13992 newlocset = xmlXPtrLocationSetCreate(NULL);
13993
13994 if (oldset != NULL) {
13995 for (i = 0; i < oldset->nodeNr; i++) {
13996 /*
13997 * Run the evaluation with a node list made of a single item
13998 * in the nodeset.
13999 */
14000 ctxt->context->node = oldset->nodeTab[i];
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014001 /*
14002 * OPTIMIZE TODO: Avoid recreation for every iteration.
14003 */
14004 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14005 ctxt->context->node);
William M. Brack08171912003-12-29 02:52:11 +000014006 valuePush(ctxt, tmp);
14007
14008 if (op->ch2 != -1)
14009 total +=
14010 xmlXPathCompOpEval(ctxt,
14011 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000014012 if (ctxt->error != XPATH_EXPRESSION_OK) {
14013 xmlXPathFreeObject(obj);
14014 return(0);
14015 }
William M. Brack08171912003-12-29 02:52:11 +000014016
William M. Brack08171912003-12-29 02:52:11 +000014017 res = valuePop(ctxt);
14018 range =
14019 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
14020 res);
14021 if (range != NULL) {
14022 xmlXPtrLocationSetAdd(newlocset, range);
14023 }
14024
14025 /*
14026 * Cleanup
14027 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014028 if (res != NULL) {
14029 xmlXPathReleaseObject(ctxt->context, res);
14030 }
William M. Brack08171912003-12-29 02:52:11 +000014031 if (ctxt->value == tmp) {
14032 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014033 xmlXPathReleaseObject(ctxt->context, res);
William M. Brack08171912003-12-29 02:52:11 +000014034 }
14035
14036 ctxt->context->node = NULL;
14037 }
14038 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014039 }
14040
14041 /*
14042 * The result is used as the new evaluation set.
14043 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014044 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000014045 ctxt->context->node = NULL;
14046 ctxt->context->contextSize = -1;
14047 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000014048 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000014049 return (total);
14050 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014051#endif /* LIBXML_XPTR_ENABLED */
14052 }
14053 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000014054 "XPath: unknown precompiled operation %d\n", op->op);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080014055 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf06307e2001-07-03 10:35:50 +000014056 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014057}
14058
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014059/**
14060 * xmlXPathCompOpEvalToBoolean:
14061 * @ctxt: the XPath parser context
14062 *
14063 * Evaluates if the expression evaluates to true.
14064 *
14065 * Returns 1 if true, 0 if false and -1 on API or internal errors.
14066 */
14067static int
14068xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014069 xmlXPathStepOpPtr op,
14070 int isPredicate)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014071{
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014072 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014073
14074start:
14075 /* comp = ctxt->comp; */
14076 switch (op->op) {
14077 case XPATH_OP_END:
14078 return (0);
14079 case XPATH_OP_VALUE:
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014080 resObj = (xmlXPathObjectPtr) op->value4;
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000014081 if (isPredicate)
14082 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14083 return(xmlXPathCastToBoolean(resObj));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014084 case XPATH_OP_SORT:
14085 /*
14086 * We don't need sorting for boolean results. Skip this one.
14087 */
14088 if (op->ch1 != -1) {
14089 op = &ctxt->comp->steps[op->ch1];
14090 goto start;
14091 }
14092 return(0);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014093 case XPATH_OP_COLLECT:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014094 if (op->ch1 == -1)
14095 return(0);
14096
14097 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14098 if (ctxt->error != XPATH_EXPRESSION_OK)
14099 return(-1);
14100
14101 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14102 if (ctxt->error != XPATH_EXPRESSION_OK)
14103 return(-1);
14104
14105 resObj = valuePop(ctxt);
14106 if (resObj == NULL)
14107 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014108 break;
14109 default:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014110 /*
14111 * Fallback to call xmlXPathCompOpEval().
14112 */
14113 xmlXPathCompOpEval(ctxt, op);
14114 if (ctxt->error != XPATH_EXPRESSION_OK)
14115 return(-1);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014116
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014117 resObj = valuePop(ctxt);
14118 if (resObj == NULL)
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000014119 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014120 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014121 }
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014122
14123 if (resObj) {
14124 int res;
14125
14126 if (resObj->type == XPATH_BOOLEAN) {
14127 res = resObj->boolval;
14128 } else if (isPredicate) {
14129 /*
14130 * For predicates a result of type "number" is handled
14131 * differently:
14132 * SPEC XPath 1.0:
14133 * "If the result is a number, the result will be converted
14134 * to true if the number is equal to the context position
14135 * and will be converted to false otherwise;"
14136 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000014137 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014138 } else {
14139 res = xmlXPathCastToBoolean(resObj);
14140 }
14141 xmlXPathReleaseObject(ctxt->context, resObj);
14142 return(res);
14143 }
14144
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014145 return(0);
14146}
14147
Daniel Veillard56de87e2005-02-16 00:22:29 +000014148#ifdef XPATH_STREAMING
14149/**
14150 * xmlXPathRunStreamEval:
14151 * @ctxt: the XPath parser context with the compiled expression
14152 *
14153 * Evaluate the Precompiled Streamable XPath expression in the given context.
14154 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014155static int
14156xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14157 xmlXPathObjectPtr *resultSeq, int toBool)
14158{
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014159 int max_depth, min_depth;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014160 int from_root;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014161 int ret, depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014162 int eval_all_nodes;
William M. Brack12d37ab2005-02-21 13:54:07 +000014163 xmlNodePtr cur = NULL, limit = NULL;
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014164 xmlStreamCtxtPtr patstream = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014165
14166 int nb_nodes = 0;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014167
14168 if ((ctxt == NULL) || (comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014169 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014170 max_depth = xmlPatternMaxDepth(comp);
14171 if (max_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014172 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014173 if (max_depth == -2)
14174 max_depth = 10000;
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014175 min_depth = xmlPatternMinDepth(comp);
14176 if (min_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014177 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014178 from_root = xmlPatternFromRoot(comp);
14179 if (from_root < 0)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014180 return(-1);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014181#if 0
14182 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14183#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000014184
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014185 if (! toBool) {
14186 if (resultSeq == NULL)
14187 return(-1);
14188 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14189 if (*resultSeq == NULL)
14190 return(-1);
14191 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014192
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014193 /*
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014194 * handle the special cases of "/" amd "." being matched
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014195 */
14196 if (min_depth == 0) {
14197 if (from_root) {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014198 /* Select "/" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014199 if (toBool)
14200 return(1);
14201 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14202 (xmlNodePtr) ctxt->doc);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014203 } else {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014204 /* Select "self::node()" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014205 if (toBool)
14206 return(1);
14207 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014208 }
14209 }
14210 if (max_depth == 0) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014211 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014212 }
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014213
Daniel Veillard56de87e2005-02-16 00:22:29 +000014214 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000014215 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014216 } else if (ctxt->node != NULL) {
14217 switch (ctxt->node->type) {
14218 case XML_ELEMENT_NODE:
14219 case XML_DOCUMENT_NODE:
14220 case XML_DOCUMENT_FRAG_NODE:
14221 case XML_HTML_DOCUMENT_NODE:
14222#ifdef LIBXML_DOCB_ENABLED
14223 case XML_DOCB_DOCUMENT_NODE:
14224#endif
14225 cur = ctxt->node;
14226 break;
14227 case XML_ATTRIBUTE_NODE:
14228 case XML_TEXT_NODE:
14229 case XML_CDATA_SECTION_NODE:
14230 case XML_ENTITY_REF_NODE:
14231 case XML_ENTITY_NODE:
14232 case XML_PI_NODE:
14233 case XML_COMMENT_NODE:
14234 case XML_NOTATION_NODE:
14235 case XML_DTD_NODE:
14236 case XML_DOCUMENT_TYPE_NODE:
14237 case XML_ELEMENT_DECL:
14238 case XML_ATTRIBUTE_DECL:
14239 case XML_ENTITY_DECL:
14240 case XML_NAMESPACE_DECL:
14241 case XML_XINCLUDE_START:
14242 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000014243 break;
14244 }
14245 limit = cur;
14246 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014247 if (cur == NULL) {
14248 return(0);
14249 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014250
14251 patstream = xmlPatternGetStreamCtxt(comp);
14252 if (patstream == NULL) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014253 /*
14254 * QUESTION TODO: Is this an error?
14255 */
14256 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014257 }
14258
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014259 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014260
Daniel Veillard56de87e2005-02-16 00:22:29 +000014261 if (from_root) {
14262 ret = xmlStreamPush(patstream, NULL, NULL);
14263 if (ret < 0) {
14264 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014265 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014266 goto return_1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014267 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014268 }
14269 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014270 depth = 0;
14271 goto scan_children;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014272next_node:
Daniel Veillardd3ff7ef2006-02-27 19:43:17 +000014273 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014274 nb_nodes++;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014275
14276 switch (cur->type) {
14277 case XML_ELEMENT_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014278 case XML_TEXT_NODE:
14279 case XML_CDATA_SECTION_NODE:
14280 case XML_COMMENT_NODE:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014281 case XML_PI_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014282 if (cur->type == XML_ELEMENT_NODE) {
14283 ret = xmlStreamPush(patstream, cur->name,
Daniel Veillard56de87e2005-02-16 00:22:29 +000014284 (cur->ns ? cur->ns->href : NULL));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014285 } else if (eval_all_nodes)
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014286 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14287 else
14288 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014289
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014290 if (ret < 0) {
14291 /* NOP. */
14292 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014293 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014294 goto return_1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014295 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014296 }
14297 if ((cur->children == NULL) || (depth >= max_depth)) {
14298 ret = xmlStreamPop(patstream);
14299 while (cur->next != NULL) {
14300 cur = cur->next;
14301 if ((cur->type != XML_ENTITY_DECL) &&
14302 (cur->type != XML_DTD_NODE))
14303 goto next_node;
14304 }
14305 }
14306 default:
14307 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014308 }
14309
Daniel Veillard56de87e2005-02-16 00:22:29 +000014310scan_children:
14311 if ((cur->children != NULL) && (depth < max_depth)) {
14312 /*
Daniel Veillard45490ae2008-07-29 09:13:19 +000014313 * Do not descend on entities declarations
Daniel Veillard56de87e2005-02-16 00:22:29 +000014314 */
14315 if (cur->children->type != XML_ENTITY_DECL) {
14316 cur = cur->children;
14317 depth++;
14318 /*
14319 * Skip DTDs
14320 */
14321 if (cur->type != XML_DTD_NODE)
14322 continue;
14323 }
14324 }
14325
14326 if (cur == limit)
14327 break;
14328
14329 while (cur->next != NULL) {
14330 cur = cur->next;
14331 if ((cur->type != XML_ENTITY_DECL) &&
14332 (cur->type != XML_DTD_NODE))
14333 goto next_node;
14334 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014335
Daniel Veillard56de87e2005-02-16 00:22:29 +000014336 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014337 cur = cur->parent;
14338 depth--;
14339 if ((cur == NULL) || (cur == limit))
14340 goto done;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014341 if (cur->type == XML_ELEMENT_NODE) {
14342 ret = xmlStreamPop(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014343 } else if ((eval_all_nodes) &&
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014344 ((cur->type == XML_TEXT_NODE) ||
14345 (cur->type == XML_CDATA_SECTION_NODE) ||
14346 (cur->type == XML_COMMENT_NODE) ||
14347 (cur->type == XML_PI_NODE)))
14348 {
14349 ret = xmlStreamPop(patstream);
14350 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014351 if (cur->next != NULL) {
14352 cur = cur->next;
14353 break;
14354 }
14355 } while (cur != NULL);
14356
14357 } while ((cur != NULL) && (depth >= 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014358
Daniel Veillard56de87e2005-02-16 00:22:29 +000014359done:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014360
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014361#if 0
14362 printf("stream eval: checked %d nodes selected %d\n",
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014363 nb_nodes, retObj->nodesetval->nodeNr);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014364#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014365
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014366 if (patstream)
14367 xmlFreeStreamCtxt(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014368 return(0);
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014369
14370return_1:
14371 if (patstream)
14372 xmlFreeStreamCtxt(patstream);
14373 return(1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014374}
14375#endif /* XPATH_STREAMING */
14376
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014377/**
14378 * xmlXPathRunEval:
14379 * @ctxt: the XPath parser context with the compiled expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014380 * @toBool: evaluate to a boolean result
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014381 *
14382 * Evaluate the Precompiled XPath expression in the given context.
14383 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014384static int
14385xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14386{
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014387 xmlXPathCompExprPtr comp;
14388
14389 if ((ctxt == NULL) || (ctxt->comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014390 return(-1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014391
14392 if (ctxt->valueTab == NULL) {
14393 /* Allocate the value stack */
Daniel Veillard45490ae2008-07-29 09:13:19 +000014394 ctxt->valueTab = (xmlXPathObjectPtr *)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014395 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14396 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000014397 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014398 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014399 }
14400 ctxt->valueNr = 0;
14401 ctxt->valueMax = 10;
14402 ctxt->value = NULL;
Daniel Veillardf5048b32011-08-18 17:10:13 +080014403 ctxt->valueFrame = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014404 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014405#ifdef XPATH_STREAMING
14406 if (ctxt->comp->stream) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014407 int res;
14408
14409 if (toBool) {
14410 /*
14411 * Evaluation to boolean result.
14412 */
14413 res = xmlXPathRunStreamEval(ctxt->context,
14414 ctxt->comp->stream, NULL, 1);
14415 if (res != -1)
14416 return(res);
14417 } else {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014418 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014419
14420 /*
14421 * Evaluation to a sequence.
14422 */
14423 res = xmlXPathRunStreamEval(ctxt->context,
14424 ctxt->comp->stream, &resObj, 0);
14425
14426 if ((res != -1) && (resObj != NULL)) {
14427 valuePush(ctxt, resObj);
14428 return(0);
14429 }
14430 if (resObj != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +000014431 xmlXPathReleaseObject(ctxt->context, resObj);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014432 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014433 /*
14434 * QUESTION TODO: This falls back to normal XPath evaluation
14435 * if res == -1. Is this intended?
14436 */
Daniel Veillard56de87e2005-02-16 00:22:29 +000014437 }
14438#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014439 comp = ctxt->comp;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014440 if (comp->last < 0) {
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014441 xmlGenericError(xmlGenericErrorContext,
14442 "xmlXPathRunEval: last is less than zero\n");
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014443 return(-1);
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014444 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014445 if (toBool)
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014446 return(xmlXPathCompOpEvalToBoolean(ctxt,
14447 &comp->steps[comp->last], 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014448 else
14449 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14450
14451 return(0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014452}
14453
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014454/************************************************************************
14455 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +000014456 * Public interfaces *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014457 * *
14458 ************************************************************************/
14459
14460/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014461 * xmlXPathEvalPredicate:
14462 * @ctxt: the XPath context
14463 * @res: the Predicate Expression evaluation result
14464 *
14465 * Evaluate a predicate result for the current node.
14466 * A PredicateExpr is evaluated by evaluating the Expr and converting
14467 * the result to a boolean. If the result is a number, the result will
14468 * be converted to true if the number is equal to the position of the
14469 * context node in the context node list (as returned by the position
14470 * function) and will be converted to false otherwise; if the result
14471 * is not a number, then the result will be converted as if by a call
Daniel Veillard45490ae2008-07-29 09:13:19 +000014472 * to the boolean function.
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014473 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014474 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014475 */
14476int
14477xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014478 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014479 switch (res->type) {
14480 case XPATH_BOOLEAN:
14481 return(res->boolval);
14482 case XPATH_NUMBER:
14483 return(res->floatval == ctxt->proximityPosition);
14484 case XPATH_NODESET:
14485 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000014486 if (res->nodesetval == NULL)
14487 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014488 return(res->nodesetval->nodeNr != 0);
14489 case XPATH_STRING:
14490 return((res->stringval != NULL) &&
14491 (xmlStrlen(res->stringval) != 0));
14492 default:
14493 STRANGE
14494 }
14495 return(0);
14496}
14497
14498/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014499 * xmlXPathEvaluatePredicateResult:
14500 * @ctxt: the XPath Parser context
14501 * @res: the Predicate Expression evaluation result
14502 *
14503 * Evaluate a predicate result for the current node.
14504 * A PredicateExpr is evaluated by evaluating the Expr and converting
14505 * the result to a boolean. If the result is a number, the result will
14506 * be converted to true if the number is equal to the position of the
14507 * context node in the context node list (as returned by the position
14508 * function) and will be converted to false otherwise; if the result
14509 * is not a number, then the result will be converted as if by a call
Daniel Veillard45490ae2008-07-29 09:13:19 +000014510 * to the boolean function.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014511 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014512 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014513 */
14514int
Daniel Veillard45490ae2008-07-29 09:13:19 +000014515xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014516 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014517 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014518 switch (res->type) {
14519 case XPATH_BOOLEAN:
14520 return(res->boolval);
14521 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000014522#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000014523 return((res->floatval == ctxt->context->proximityPosition) &&
14524 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000014525#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014526 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000014527#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014528 case XPATH_NODESET:
14529 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000014530 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000014531 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014532 return(res->nodesetval->nodeNr != 0);
14533 case XPATH_STRING:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014534 return((res->stringval != NULL) && (res->stringval[0] != 0));
William M. Brack08171912003-12-29 02:52:11 +000014535#ifdef LIBXML_XPTR_ENABLED
14536 case XPATH_LOCATIONSET:{
14537 xmlLocationSetPtr ptr = res->user;
14538 if (ptr == NULL)
14539 return(0);
14540 return (ptr->locNr != 0);
14541 }
14542#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014543 default:
14544 STRANGE
14545 }
14546 return(0);
14547}
14548
Daniel Veillard56de87e2005-02-16 00:22:29 +000014549#ifdef XPATH_STREAMING
14550/**
14551 * xmlXPathTryStreamCompile:
14552 * @ctxt: an XPath context
14553 * @str: the XPath expression
14554 *
14555 * Try to compile the XPath expression as a streamable subset.
14556 *
14557 * Returns the compiled expression or NULL if failed to compile.
14558 */
14559static xmlXPathCompExprPtr
14560xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14561 /*
14562 * Optimization: use streaming patterns when the XPath expression can
14563 * be compiled to a stream lookup
14564 */
14565 xmlPatternPtr stream;
14566 xmlXPathCompExprPtr comp;
14567 xmlDictPtr dict = NULL;
14568 const xmlChar **namespaces = NULL;
14569 xmlNsPtr ns;
14570 int i, j;
14571
14572 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14573 (!xmlStrchr(str, '@'))) {
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014574 const xmlChar *tmp;
14575
14576 /*
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014577 * We don't try to handle expressions using the verbose axis
14578 * specifiers ("::"), just the simplied form at this point.
14579 * Additionally, if there is no list of namespaces available and
14580 * there's a ":" in the expression, indicating a prefixed QName,
14581 * then we won't try to compile either. xmlPatterncompile() needs
14582 * to have a list of namespaces at compilation time in order to
14583 * compile prefixed name tests.
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014584 */
14585 tmp = xmlStrchr(str, ':');
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014586 if ((tmp != NULL) &&
14587 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
Daniel Veillard45490ae2008-07-29 09:13:19 +000014588 return(NULL);
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014589
Daniel Veillard56de87e2005-02-16 00:22:29 +000014590 if (ctxt != NULL) {
14591 dict = ctxt->dict;
14592 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000014593 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000014594 if (namespaces == NULL) {
14595 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14596 return(NULL);
14597 }
14598 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14599 ns = ctxt->namespaces[j];
14600 namespaces[i++] = ns->href;
14601 namespaces[i++] = ns->prefix;
14602 }
14603 namespaces[i++] = NULL;
Daniel Veillard13cee4e2009-09-05 14:52:55 +020014604 namespaces[i] = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014605 }
14606 }
14607
William M. Brackea152c02005-06-09 18:12:28 +000014608 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14609 &namespaces[0]);
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014610 if (namespaces != NULL) {
14611 xmlFree((xmlChar **)namespaces);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014612 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014613 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14614 comp = xmlXPathNewCompExpr();
14615 if (comp == NULL) {
14616 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14617 return(NULL);
14618 }
14619 comp->stream = stream;
14620 comp->dict = dict;
14621 if (comp->dict)
14622 xmlDictReference(comp->dict);
14623 return(comp);
14624 }
14625 xmlFreePattern(stream);
14626 }
14627 return(NULL);
14628}
14629#endif /* XPATH_STREAMING */
14630
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014631static int
14632xmlXPathCanRewriteDosExpression(xmlChar *expr)
14633{
14634 if (expr == NULL)
14635 return(0);
14636 do {
14637 if ((*expr == '/') && (*(++expr) == '/'))
14638 return(1);
14639 } while (*expr++);
14640 return(0);
14641}
14642static void
14643xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14644{
14645 /*
14646 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14647 * internal representation.
14648 */
14649 if (op->ch1 != -1) {
14650 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +000014651 ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014652 ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
14653 ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
14654 {
14655 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014656 * This is a "child::foo"
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014657 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000014658 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014659
14660 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +000014661 (prevop->ch1 != -1) &&
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014662 ((xmlXPathAxisVal) prevop->value ==
14663 AXIS_DESCENDANT_OR_SELF) &&
14664 (prevop->ch2 == -1) &&
14665 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014666 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
14667 (comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
Daniel Veillard45490ae2008-07-29 09:13:19 +000014668 {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014669 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014670 * This is a "/descendant-or-self::node()" without predicates.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014671 * Eliminate it.
14672 */
14673 op->ch1 = prevop->ch1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014674 op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014675 }
14676 }
14677 if (op->ch1 != -1)
14678 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
14679 }
14680 if (op->ch2 != -1)
14681 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
14682}
14683
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014684/**
Daniel Veillard4773df22004-01-23 13:15:13 +000014685 * xmlXPathCtxtCompile:
14686 * @ctxt: an XPath context
14687 * @str: the XPath expression
14688 *
14689 * Compile an XPath expression
14690 *
14691 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14692 * the caller has to free the object.
14693 */
14694xmlXPathCompExprPtr
14695xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14696 xmlXPathParserContextPtr pctxt;
14697 xmlXPathCompExprPtr comp;
14698
Daniel Veillard56de87e2005-02-16 00:22:29 +000014699#ifdef XPATH_STREAMING
14700 comp = xmlXPathTryStreamCompile(ctxt, str);
14701 if (comp != NULL)
14702 return(comp);
14703#endif
14704
Daniel Veillard4773df22004-01-23 13:15:13 +000014705 xmlXPathInit();
14706
14707 pctxt = xmlXPathNewParserContext(str, ctxt);
William M. Brack11be2d02007-01-24 19:17:19 +000014708 if (pctxt == NULL)
14709 return NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014710 xmlXPathCompileExpr(pctxt, 1);
Daniel Veillard4773df22004-01-23 13:15:13 +000014711
14712 if( pctxt->error != XPATH_EXPRESSION_OK )
14713 {
14714 xmlXPathFreeParserContext(pctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000014715 return(NULL);
Daniel Veillard4773df22004-01-23 13:15:13 +000014716 }
14717
14718 if (*pctxt->cur != 0) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014719 /*
Daniel Veillard4773df22004-01-23 13:15:13 +000014720 * aleksey: in some cases this line prints *second* error message
14721 * (see bug #78858) and probably this should be fixed.
14722 * However, we are not sure that all error messages are printed
14723 * out in other places. It's not critical so we leave it as-is for now
14724 */
14725 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14726 comp = NULL;
14727 } else {
14728 comp = pctxt->comp;
14729 pctxt->comp = NULL;
14730 }
14731 xmlXPathFreeParserContext(pctxt);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014732
Daniel Veillard4773df22004-01-23 13:15:13 +000014733 if (comp != NULL) {
14734 comp->expr = xmlStrdup(str);
14735#ifdef DEBUG_EVAL_COUNTS
14736 comp->string = xmlStrdup(str);
14737 comp->nb = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014738#endif
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014739 if ((comp->expr != NULL) &&
14740 (comp->nbStep > 2) &&
14741 (comp->last >= 0) &&
Kasimier T. Buchcik7cb3fa92006-06-06 15:27:46 +000014742 (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
14743 {
14744 xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014745 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014746 }
Daniel Veillard4773df22004-01-23 13:15:13 +000014747 return(comp);
14748}
14749
14750/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014751 * xmlXPathCompile:
14752 * @str: the XPath expression
14753 *
14754 * Compile an XPath expression
14755 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000014756 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014757 * the caller has to free the object.
14758 */
14759xmlXPathCompExprPtr
14760xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000014761 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014762}
14763
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014764/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014765 * xmlXPathCompiledEvalInternal:
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014766 * @comp: the compiled XPath expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014767 * @ctxt: the XPath context
14768 * @resObj: the resulting XPath object or NULL
14769 * @toBool: 1 if only a boolean result is requested
Owen Taylor3473f882001-02-23 17:55:21 +000014770 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014771 * Evaluate the Precompiled XPath expression in the given context.
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014772 * The caller has to free @resObj.
Owen Taylor3473f882001-02-23 17:55:21 +000014773 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014774 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000014775 * the caller has to free the object.
14776 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014777static int
14778xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14779 xmlXPathContextPtr ctxt,
14780 xmlXPathObjectPtr *resObj,
14781 int toBool)
14782{
Daniel Veillard45490ae2008-07-29 09:13:19 +000014783 xmlXPathParserContextPtr pctxt;
Daniel Veillard81463942001-10-16 12:34:39 +000014784#ifndef LIBXML_THREAD_ENABLED
14785 static int reentance = 0;
14786#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014787 int res;
Owen Taylor3473f882001-02-23 17:55:21 +000014788
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014789 CHECK_CTXT_NEG(ctxt)
William M. Brackf13f77f2004-11-12 16:03:48 +000014790
14791 if (comp == NULL)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014792 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +000014793 xmlXPathInit();
14794
Daniel Veillard81463942001-10-16 12:34:39 +000014795#ifndef LIBXML_THREAD_ENABLED
14796 reentance++;
14797 if (reentance > 1)
14798 xmlXPathDisableOptimizer = 1;
14799#endif
14800
Daniel Veillardf06307e2001-07-03 10:35:50 +000014801#ifdef DEBUG_EVAL_COUNTS
14802 comp->nb++;
14803 if ((comp->string != NULL) && (comp->nb > 100)) {
14804 fprintf(stderr, "100 x %s\n", comp->string);
14805 comp->nb = 0;
14806 }
14807#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014808 pctxt = xmlXPathCompParserContext(comp, ctxt);
14809 res = xmlXPathRunEval(pctxt, toBool);
Owen Taylor3473f882001-02-23 17:55:21 +000014810
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014811 if (resObj) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014812 if (pctxt->value == NULL) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014813 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014814 "xmlXPathCompiledEval: evaluation failed\n");
Daniel Veillard45490ae2008-07-29 09:13:19 +000014815 *resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014816 } else {
14817 *resObj = valuePop(pctxt);
14818 }
Owen Taylor3473f882001-02-23 17:55:21 +000014819 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014820
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014821 /*
14822 * Pop all remaining objects from the stack.
14823 */
14824 if (pctxt->valueNr > 0) {
14825 xmlXPathObjectPtr tmp;
14826 int stack = 0;
14827
14828 do {
14829 tmp = valuePop(pctxt);
14830 if (tmp != NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014831 stack++;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014832 xmlXPathReleaseObject(ctxt, tmp);
14833 }
14834 } while (tmp != NULL);
14835 if ((stack != 0) &&
14836 ((toBool) || ((resObj) && (*resObj))))
14837 {
14838 xmlGenericError(xmlGenericErrorContext,
14839 "xmlXPathCompiledEval: %d objects left on the stack.\n",
14840 stack);
14841 }
Owen Taylor3473f882001-02-23 17:55:21 +000014842 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014843
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014844 if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14845 xmlXPathFreeObject(*resObj);
14846 *resObj = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014847 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014848 pctxt->comp = NULL;
14849 xmlXPathFreeParserContext(pctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000014850#ifndef LIBXML_THREAD_ENABLED
14851 reentance--;
14852#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014853
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014854 return(res);
14855}
14856
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014857/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014858 * xmlXPathCompiledEval:
14859 * @comp: the compiled XPath expression
14860 * @ctx: the XPath context
14861 *
14862 * Evaluate the Precompiled XPath expression in the given context.
14863 *
14864 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14865 * the caller has to free the object.
14866 */
14867xmlXPathObjectPtr
14868xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14869{
14870 xmlXPathObjectPtr res = NULL;
14871
14872 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14873 return(res);
14874}
14875
14876/**
14877 * xmlXPathCompiledEvalToBoolean:
14878 * @comp: the compiled XPath expression
14879 * @ctxt: the XPath context
14880 *
14881 * Applies the XPath boolean() function on the result of the given
14882 * compiled expression.
14883 *
14884 * Returns 1 if the expression evaluated to true, 0 if to false and
14885 * -1 in API and internal errors.
14886 */
14887int
14888xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14889 xmlXPathContextPtr ctxt)
14890{
14891 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14892}
14893
14894/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014895 * xmlXPathEvalExpr:
14896 * @ctxt: the XPath Parser context
14897 *
14898 * Parse and evaluate an XPath expression in the given context,
14899 * then push the result on the context stack
14900 */
14901void
14902xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014903#ifdef XPATH_STREAMING
14904 xmlXPathCompExprPtr comp;
14905#endif
14906
Daniel Veillarda82b1822004-11-08 16:24:57 +000014907 if (ctxt == NULL) return;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014908
Daniel Veillard56de87e2005-02-16 00:22:29 +000014909#ifdef XPATH_STREAMING
14910 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14911 if (comp != NULL) {
14912 if (ctxt->comp != NULL)
14913 xmlXPathFreeCompExpr(ctxt->comp);
14914 ctxt->comp = comp;
14915 if (ctxt->cur != NULL)
14916 while (*ctxt->cur != 0) ctxt->cur++;
14917 } else
14918#endif
14919 {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014920 xmlXPathCompileExpr(ctxt, 1);
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014921 /*
14922 * In this scenario the expression string will sit in ctxt->base.
14923 */
14924 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
14925 (ctxt->comp != NULL) &&
14926 (ctxt->base != NULL) &&
Kasimier T. Buchcik7cb3fa92006-06-06 15:27:46 +000014927 (ctxt->comp->nbStep > 2) &&
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014928 (ctxt->comp->last >= 0) &&
14929 (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014930 {
14931 xmlXPathRewriteDOSExpression(ctxt->comp,
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014932 &ctxt->comp->steps[ctxt->comp->last]);
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014933 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014934 }
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000014935 CHECK_ERROR;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014936 xmlXPathRunEval(ctxt, 0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014937}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014938
14939/**
14940 * xmlXPathEval:
14941 * @str: the XPath expression
14942 * @ctx: the XPath context
14943 *
14944 * Evaluate the XPath Location Path in the given context.
14945 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014946 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014947 * the caller has to free the object.
14948 */
14949xmlXPathObjectPtr
14950xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14951 xmlXPathParserContextPtr ctxt;
14952 xmlXPathObjectPtr res, tmp, init = NULL;
14953 int stack = 0;
14954
William M. Brackf13f77f2004-11-12 16:03:48 +000014955 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014956
William M. Brackf13f77f2004-11-12 16:03:48 +000014957 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014958
14959 ctxt = xmlXPathNewParserContext(str, ctx);
William M. Brack11be2d02007-01-24 19:17:19 +000014960 if (ctxt == NULL)
14961 return NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014962 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014963
14964 if (ctxt->value == NULL) {
14965 xmlGenericError(xmlGenericErrorContext,
14966 "xmlXPathEval: evaluation failed\n");
14967 res = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014968 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
Daniel Veillard56de87e2005-02-16 00:22:29 +000014969#ifdef XPATH_STREAMING
14970 && (ctxt->comp->stream == NULL)
14971#endif
14972 ) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014973 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14974 res = NULL;
14975 } else {
14976 res = valuePop(ctxt);
14977 }
14978
14979 do {
14980 tmp = valuePop(ctxt);
14981 if (tmp != NULL) {
14982 if (tmp != init)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014983 stack++;
14984 xmlXPathReleaseObject(ctx, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014985 }
14986 } while (tmp != NULL);
14987 if ((stack != 0) && (res != NULL)) {
14988 xmlGenericError(xmlGenericErrorContext,
14989 "xmlXPathEval: %d object left on the stack\n",
14990 stack);
14991 }
14992 if (ctxt->error != XPATH_EXPRESSION_OK) {
14993 xmlXPathFreeObject(res);
14994 res = NULL;
14995 }
14996
Owen Taylor3473f882001-02-23 17:55:21 +000014997 xmlXPathFreeParserContext(ctxt);
14998 return(res);
14999}
15000
15001/**
15002 * xmlXPathEvalExpression:
15003 * @str: the XPath expression
15004 * @ctxt: the XPath context
15005 *
15006 * Evaluate the XPath expression in the given context.
15007 *
15008 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15009 * the caller has to free the object.
15010 */
15011xmlXPathObjectPtr
15012xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
15013 xmlXPathParserContextPtr pctxt;
15014 xmlXPathObjectPtr res, tmp;
15015 int stack = 0;
15016
William M. Brackf13f77f2004-11-12 16:03:48 +000015017 CHECK_CTXT(ctxt)
Owen Taylor3473f882001-02-23 17:55:21 +000015018
William M. Brackf13f77f2004-11-12 16:03:48 +000015019 xmlXPathInit();
Owen Taylor3473f882001-02-23 17:55:21 +000015020
15021 pctxt = xmlXPathNewParserContext(str, ctxt);
William M. Brack11be2d02007-01-24 19:17:19 +000015022 if (pctxt == NULL)
15023 return NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000015024 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000015025
Daniel Veillardc465ffc2006-10-17 19:39:33 +000015026 if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
Owen Taylor3473f882001-02-23 17:55:21 +000015027 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
15028 res = NULL;
15029 } else {
15030 res = valuePop(pctxt);
15031 }
15032 do {
15033 tmp = valuePop(pctxt);
15034 if (tmp != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015035 xmlXPathReleaseObject(ctxt, tmp);
Owen Taylor3473f882001-02-23 17:55:21 +000015036 stack++;
15037 }
15038 } while (tmp != NULL);
15039 if ((stack != 0) && (res != NULL)) {
15040 xmlGenericError(xmlGenericErrorContext,
15041 "xmlXPathEvalExpression: %d object left on the stack\n",
15042 stack);
15043 }
15044 xmlXPathFreeParserContext(pctxt);
15045 return(res);
15046}
15047
Daniel Veillard42766c02002-08-22 20:52:17 +000015048/************************************************************************
15049 * *
15050 * Extra functions not pertaining to the XPath spec *
15051 * *
15052 ************************************************************************/
15053/**
15054 * xmlXPathEscapeUriFunction:
15055 * @ctxt: the XPath Parser context
15056 * @nargs: the number of arguments
15057 *
15058 * Implement the escape-uri() XPath function
15059 * string escape-uri(string $str, bool $escape-reserved)
15060 *
15061 * This function applies the URI escaping rules defined in section 2 of [RFC
15062 * 2396] to the string supplied as $uri-part, which typically represents all
15063 * or part of a URI. The effect of the function is to replace any special
15064 * character in the string by an escape sequence of the form %xx%yy...,
15065 * where xxyy... is the hexadecimal representation of the octets used to
15066 * represent the character in UTF-8.
15067 *
15068 * The set of characters that are escaped depends on the setting of the
15069 * boolean argument $escape-reserved.
15070 *
15071 * If $escape-reserved is true, all characters are escaped other than lower
15072 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15073 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15074 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15075 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15076 * A-F).
15077 *
15078 * If $escape-reserved is false, the behavior differs in that characters
15079 * referred to in [RFC 2396] as reserved characters are not escaped. These
15080 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
Daniel Veillard45490ae2008-07-29 09:13:19 +000015081 *
Daniel Veillard42766c02002-08-22 20:52:17 +000015082 * [RFC 2396] does not define whether escaped URIs should use lower case or
15083 * upper case for hexadecimal digits. To ensure that escaped URIs can be
15084 * compared using string comparison functions, this function must always use
15085 * the upper-case letters A-F.
Daniel Veillard45490ae2008-07-29 09:13:19 +000015086 *
Daniel Veillard42766c02002-08-22 20:52:17 +000015087 * Generally, $escape-reserved should be set to true when escaping a string
15088 * that is to form a single part of a URI, and to false when escaping an
15089 * entire URI or URI reference.
Daniel Veillard45490ae2008-07-29 09:13:19 +000015090 *
15091 * In the case of non-ascii characters, the string is encoded according to
Daniel Veillard42766c02002-08-22 20:52:17 +000015092 * utf-8 and then converted according to RFC 2396.
15093 *
15094 * Examples
Daniel Veillard45490ae2008-07-29 09:13:19 +000015095 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
Daniel Veillard42766c02002-08-22 20:52:17 +000015096 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15097 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15098 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15099 *
15100 */
Daniel Veillard118aed72002-09-24 14:13:13 +000015101static void
Daniel Veillard42766c02002-08-22 20:52:17 +000015102xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15103 xmlXPathObjectPtr str;
15104 int escape_reserved;
Daniel Veillardade10f22012-07-12 09:43:27 +080015105 xmlBufPtr target;
Daniel Veillard42766c02002-08-22 20:52:17 +000015106 xmlChar *cptr;
15107 xmlChar escape[4];
Daniel Veillard45490ae2008-07-29 09:13:19 +000015108
Daniel Veillard42766c02002-08-22 20:52:17 +000015109 CHECK_ARITY(2);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015110
Daniel Veillard42766c02002-08-22 20:52:17 +000015111 escape_reserved = xmlXPathPopBoolean(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015112
Daniel Veillard42766c02002-08-22 20:52:17 +000015113 CAST_TO_STRING;
15114 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015115
Daniel Veillardade10f22012-07-12 09:43:27 +080015116 target = xmlBufCreate();
Daniel Veillard45490ae2008-07-29 09:13:19 +000015117
Daniel Veillard42766c02002-08-22 20:52:17 +000015118 escape[0] = '%';
15119 escape[3] = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000015120
Daniel Veillard42766c02002-08-22 20:52:17 +000015121 if (target) {
15122 for (cptr = str->stringval; *cptr; cptr++) {
15123 if ((*cptr >= 'A' && *cptr <= 'Z') ||
15124 (*cptr >= 'a' && *cptr <= 'z') ||
15125 (*cptr >= '0' && *cptr <= '9') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000015126 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
Daniel Veillard42766c02002-08-22 20:52:17 +000015127 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
15128 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000015129 (*cptr == '%' &&
Daniel Veillard42766c02002-08-22 20:52:17 +000015130 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15131 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15132 (cptr[1] >= '0' && cptr[1] <= '9')) &&
15133 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15134 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15135 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15136 (!escape_reserved &&
15137 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15138 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15139 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15140 *cptr == ','))) {
Daniel Veillardade10f22012-07-12 09:43:27 +080015141 xmlBufAdd(target, cptr, 1);
Daniel Veillard42766c02002-08-22 20:52:17 +000015142 } else {
15143 if ((*cptr >> 4) < 10)
15144 escape[1] = '0' + (*cptr >> 4);
15145 else
15146 escape[1] = 'A' - 10 + (*cptr >> 4);
15147 if ((*cptr & 0xF) < 10)
15148 escape[2] = '0' + (*cptr & 0xF);
15149 else
15150 escape[2] = 'A' - 10 + (*cptr & 0xF);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015151
Daniel Veillardade10f22012-07-12 09:43:27 +080015152 xmlBufAdd(target, &escape[0], 3);
Daniel Veillard42766c02002-08-22 20:52:17 +000015153 }
15154 }
15155 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015156 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +080015157 xmlBufContent(target)));
15158 xmlBufFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015159 xmlXPathReleaseObject(ctxt->context, str);
Daniel Veillard42766c02002-08-22 20:52:17 +000015160}
15161
Owen Taylor3473f882001-02-23 17:55:21 +000015162/**
15163 * xmlXPathRegisterAllFunctions:
15164 * @ctxt: the XPath context
15165 *
15166 * Registers all default XPath functions in this context
15167 */
15168void
15169xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15170{
15171 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15172 xmlXPathBooleanFunction);
15173 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15174 xmlXPathCeilingFunction);
15175 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15176 xmlXPathCountFunction);
15177 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15178 xmlXPathConcatFunction);
15179 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15180 xmlXPathContainsFunction);
15181 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15182 xmlXPathIdFunction);
15183 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15184 xmlXPathFalseFunction);
15185 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15186 xmlXPathFloorFunction);
15187 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15188 xmlXPathLastFunction);
15189 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15190 xmlXPathLangFunction);
15191 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15192 xmlXPathLocalNameFunction);
15193 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15194 xmlXPathNotFunction);
15195 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15196 xmlXPathNameFunction);
15197 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15198 xmlXPathNamespaceURIFunction);
15199 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15200 xmlXPathNormalizeFunction);
15201 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15202 xmlXPathNumberFunction);
15203 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15204 xmlXPathPositionFunction);
15205 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15206 xmlXPathRoundFunction);
15207 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15208 xmlXPathStringFunction);
15209 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15210 xmlXPathStringLengthFunction);
15211 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15212 xmlXPathStartsWithFunction);
15213 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15214 xmlXPathSubstringFunction);
15215 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15216 xmlXPathSubstringBeforeFunction);
15217 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15218 xmlXPathSubstringAfterFunction);
15219 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15220 xmlXPathSumFunction);
15221 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15222 xmlXPathTrueFunction);
15223 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15224 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000015225
15226 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15227 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15228 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000015229}
15230
15231#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000015232#define bottom_xpath
15233#include "elfgcchack.h"