blob: df0e367a990d2aa839cfe322cfbbea9109b6f46d [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
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000590typedef struct _xmlXPathStepOp xmlXPathStepOp;
591typedef xmlXPathStepOp *xmlXPathStepOpPtr;
592struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000593 xmlXPathOp op; /* The identifier of the operation */
594 int ch1; /* First child */
595 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000596 int value;
597 int value2;
598 int value3;
599 void *value4;
600 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000601 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000602 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000603};
604
605struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000606 int nbStep; /* Number of steps in this expression */
607 int maxStep; /* Maximum number of steps allocated */
608 xmlXPathStepOp *steps; /* ops for computation of this expression */
609 int last; /* index of last step in expression */
610 xmlChar *expr; /* the expression being computed */
Daniel Veillard4773df22004-01-23 13:15:13 +0000611 xmlDictPtr dict; /* the dictionnary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000612#ifdef DEBUG_EVAL_COUNTS
613 int nb;
614 xmlChar *string;
615#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000616#ifdef XPATH_STREAMING
617 xmlPatternPtr stream;
618#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000619};
620
621/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000622 * *
623 * Forward declarations *
624 * *
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000625 ************************************************************************/
626static void
627xmlXPathFreeValueTree(xmlNodeSetPtr obj);
628static void
629xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
630static int
631xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
632 xmlXPathStepOpPtr op, xmlNodePtr *first);
633static int
634xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +0000635 xmlXPathStepOpPtr op,
636 int isPredicate);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000637
638/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000639 * *
640 * Parser Type functions *
641 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000642 ************************************************************************/
643
644/**
645 * xmlXPathNewCompExpr:
646 *
647 * Create a new Xpath component
648 *
649 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
650 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000651static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000652xmlXPathNewCompExpr(void) {
653 xmlXPathCompExprPtr cur;
654
655 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
656 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000657 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000658 return(NULL);
659 }
660 memset(cur, 0, sizeof(xmlXPathCompExpr));
661 cur->maxStep = 10;
662 cur->nbStep = 0;
663 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
664 sizeof(xmlXPathStepOp));
665 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000666 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000667 xmlFree(cur);
668 return(NULL);
669 }
670 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
671 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000672#ifdef DEBUG_EVAL_COUNTS
673 cur->nb = 0;
674#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000675 return(cur);
676}
677
678/**
679 * xmlXPathFreeCompExpr:
680 * @comp: an XPATH comp
681 *
682 * Free up the memory allocated by @comp
683 */
684void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000685xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
686{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000687 xmlXPathStepOpPtr op;
688 int i;
689
690 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000691 return;
Daniel Veillard4773df22004-01-23 13:15:13 +0000692 if (comp->dict == NULL) {
693 for (i = 0; i < comp->nbStep; i++) {
694 op = &comp->steps[i];
695 if (op->value4 != NULL) {
696 if (op->op == XPATH_OP_VALUE)
697 xmlXPathFreeObject(op->value4);
698 else
699 xmlFree(op->value4);
700 }
701 if (op->value5 != NULL)
702 xmlFree(op->value5);
703 }
704 } else {
705 for (i = 0; i < comp->nbStep; i++) {
706 op = &comp->steps[i];
707 if (op->value4 != NULL) {
708 if (op->op == XPATH_OP_VALUE)
709 xmlXPathFreeObject(op->value4);
710 }
711 }
712 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000713 }
714 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000715 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000716 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000717#ifdef DEBUG_EVAL_COUNTS
718 if (comp->string != NULL) {
719 xmlFree(comp->string);
720 }
721#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000722#ifdef XPATH_STREAMING
723 if (comp->stream != NULL) {
724 xmlFreePatternList(comp->stream);
725 }
726#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000727 if (comp->expr != NULL) {
728 xmlFree(comp->expr);
729 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000730
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000731 xmlFree(comp);
732}
733
734/**
735 * xmlXPathCompExprAdd:
736 * @comp: the compiled expression
737 * @ch1: first child index
738 * @ch2: second child index
739 * @op: an op
740 * @value: the first int value
741 * @value2: the second int value
742 * @value3: the third int value
743 * @value4: the first string value
744 * @value5: the second string value
745 *
William M. Brack08171912003-12-29 02:52:11 +0000746 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000747 *
748 * Returns -1 in case of failure, the index otherwise
749 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000750static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000751xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
752 xmlXPathOp op, int value,
753 int value2, int value3, void *value4, void *value5) {
754 if (comp->nbStep >= comp->maxStep) {
755 xmlXPathStepOp *real;
756
Daniel Veillardcd852ad2012-07-30 10:12:18 +0800757 if (comp->maxStep >= XPATH_MAX_STEPS) {
758 xmlXPathErrMemory(NULL, "adding step\n");
759 return(-1);
760 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000761 comp->maxStep *= 2;
762 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
763 comp->maxStep * sizeof(xmlXPathStepOp));
764 if (real == NULL) {
765 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000766 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000767 return(-1);
768 }
769 comp->steps = real;
770 }
771 comp->last = comp->nbStep;
772 comp->steps[comp->nbStep].ch1 = ch1;
773 comp->steps[comp->nbStep].ch2 = ch2;
774 comp->steps[comp->nbStep].op = op;
775 comp->steps[comp->nbStep].value = value;
776 comp->steps[comp->nbStep].value2 = value2;
777 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +0000778 if ((comp->dict != NULL) &&
779 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
780 (op == XPATH_OP_COLLECT))) {
781 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000782 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000783 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000784 xmlFree(value4);
785 } else
786 comp->steps[comp->nbStep].value4 = NULL;
787 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000788 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000789 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000790 xmlFree(value5);
791 } else
792 comp->steps[comp->nbStep].value5 = NULL;
793 } else {
794 comp->steps[comp->nbStep].value4 = value4;
795 comp->steps[comp->nbStep].value5 = value5;
796 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000797 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000798 return(comp->nbStep++);
799}
800
Daniel Veillardf06307e2001-07-03 10:35:50 +0000801/**
802 * xmlXPathCompSwap:
803 * @comp: the compiled expression
804 * @op: operation index
805 *
806 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000807 */
808static void
809xmlXPathCompSwap(xmlXPathStepOpPtr op) {
810 int tmp;
811
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000812#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000813 /*
814 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +0000815 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +0000816 * application
817 */
818 if (xmlXPathDisableOptimizer)
819 return;
820#endif
821
Daniel Veillardf06307e2001-07-03 10:35:50 +0000822 tmp = op->ch1;
823 op->ch1 = op->ch2;
824 op->ch2 = tmp;
825}
826
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000827#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
828 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
829 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000830#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
831 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
832 (op), (val), (val2), (val3), (val4), (val5))
833
Daniel Veillard45490ae2008-07-29 09:13:19 +0000834#define PUSH_LEAVE_EXPR(op, val, val2) \
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000835xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
836
Daniel Veillard45490ae2008-07-29 09:13:19 +0000837#define PUSH_UNARY_EXPR(op, ch, val, val2) \
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000838xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
839
Daniel Veillard45490ae2008-07-29 09:13:19 +0000840#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +0000841xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
842 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000843
844/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000845 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +0000846 * XPath object cache structures *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000847 * *
848 ************************************************************************/
849
850/* #define XP_DEFAULT_CACHE_ON */
851
Kasimier T. Buchcik58694692006-05-31 12:37:28 +0000852#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000853
Kasimier T. Buchcik58694692006-05-31 12:37:28 +0000854typedef struct _xmlXPathContextCache xmlXPathContextCache;
855typedef xmlXPathContextCache *xmlXPathContextCachePtr;
856struct _xmlXPathContextCache {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +0000857 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
858 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
859 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
860 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
861 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000862 int maxNodeset;
863 int maxString;
864 int maxBoolean;
865 int maxNumber;
866 int maxMisc;
867#ifdef XP_DEBUG_OBJ_USAGE
868 int dbgCachedAll;
869 int dbgCachedNodeset;
870 int dbgCachedString;
871 int dbgCachedBool;
872 int dbgCachedNumber;
873 int dbgCachedPoint;
874 int dbgCachedRange;
875 int dbgCachedLocset;
876 int dbgCachedUsers;
877 int dbgCachedXSLTTree;
Daniel Veillard45490ae2008-07-29 09:13:19 +0000878 int dbgCachedUndefined;
879
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000880
881 int dbgReusedAll;
882 int dbgReusedNodeset;
883 int dbgReusedString;
884 int dbgReusedBool;
885 int dbgReusedNumber;
886 int dbgReusedPoint;
887 int dbgReusedRange;
888 int dbgReusedLocset;
889 int dbgReusedUsers;
890 int dbgReusedXSLTTree;
891 int dbgReusedUndefined;
892
893#endif
894};
895
896/************************************************************************
897 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +0000898 * Debugging related functions *
Owen Taylor3473f882001-02-23 17:55:21 +0000899 * *
900 ************************************************************************/
901
Daniel Veillard45490ae2008-07-29 09:13:19 +0000902#define STRANGE \
Owen Taylor3473f882001-02-23 17:55:21 +0000903 xmlGenericError(xmlGenericErrorContext, \
904 "Internal error at %s:%d\n", \
905 __FILE__, __LINE__);
906
907#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000908static void
909xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000910 int i;
911 char shift[100];
912
913 for (i = 0;((i < depth) && (i < 25));i++)
914 shift[2 * i] = shift[2 * i + 1] = ' ';
915 shift[2 * i] = shift[2 * i + 1] = 0;
916 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200917 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +0000918 fprintf(output, "Node is NULL !\n");
919 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +0000920
Owen Taylor3473f882001-02-23 17:55:21 +0000921 }
922
923 if ((cur->type == XML_DOCUMENT_NODE) ||
924 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200925 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +0000926 fprintf(output, " /\n");
927 } else if (cur->type == XML_ATTRIBUTE_NODE)
928 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
929 else
930 xmlDebugDumpOneNode(output, cur, depth);
931}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000932static void
933xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000934 xmlNodePtr tmp;
935 int i;
936 char shift[100];
937
938 for (i = 0;((i < depth) && (i < 25));i++)
939 shift[2 * i] = shift[2 * i + 1] = ' ';
940 shift[2 * i] = shift[2 * i + 1] = 0;
941 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200942 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000943 fprintf(output, "Node is NULL !\n");
944 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +0000945
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000946 }
947
948 while (cur != NULL) {
949 tmp = cur;
950 cur = cur->next;
951 xmlDebugDumpOneNode(output, tmp, depth);
952 }
953}
Owen Taylor3473f882001-02-23 17:55:21 +0000954
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000955static void
956xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000957 int i;
958 char shift[100];
959
960 for (i = 0;((i < depth) && (i < 25));i++)
961 shift[2 * i] = shift[2 * i + 1] = ' ';
962 shift[2 * i] = shift[2 * i + 1] = 0;
963
964 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200965 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +0000966 fprintf(output, "NodeSet is NULL !\n");
967 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +0000968
Owen Taylor3473f882001-02-23 17:55:21 +0000969 }
970
Daniel Veillard911f49a2001-04-07 15:39:35 +0000971 if (cur != NULL) {
972 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
973 for (i = 0;i < cur->nodeNr;i++) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200974 fprintf(output, "%s", shift);
Daniel Veillard911f49a2001-04-07 15:39:35 +0000975 fprintf(output, "%d", i + 1);
976 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
977 }
Owen Taylor3473f882001-02-23 17:55:21 +0000978 }
979}
980
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000981static void
982xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000983 int i;
984 char shift[100];
985
986 for (i = 0;((i < depth) && (i < 25));i++)
987 shift[2 * i] = shift[2 * i + 1] = ' ';
988 shift[2 * i] = shift[2 * i + 1] = 0;
989
990 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200991 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000992 fprintf(output, "Value Tree is NULL !\n");
993 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +0000994
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000995 }
996
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200997 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000998 fprintf(output, "%d", i + 1);
999 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1000}
Owen Taylor3473f882001-02-23 17:55:21 +00001001#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001002static void
1003xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001004 int i;
1005 char shift[100];
1006
1007 for (i = 0;((i < depth) && (i < 25));i++)
1008 shift[2 * i] = shift[2 * i + 1] = ' ';
1009 shift[2 * i] = shift[2 * i + 1] = 0;
1010
1011 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001012 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001013 fprintf(output, "LocationSet is NULL !\n");
1014 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001015
Owen Taylor3473f882001-02-23 17:55:21 +00001016 }
1017
1018 for (i = 0;i < cur->locNr;i++) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001019 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001020 fprintf(output, "%d : ", i + 1);
1021 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1022 }
1023}
Daniel Veillard017b1082001-06-21 11:20:21 +00001024#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001025
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00001026/**
1027 * xmlXPathDebugDumpObject:
1028 * @output: the FILE * to dump the output
1029 * @cur: the object to inspect
1030 * @depth: indentation level
1031 *
1032 * Dump the content of the object for debugging purposes
1033 */
1034void
1035xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001036 int i;
1037 char shift[100];
1038
Daniel Veillarda82b1822004-11-08 16:24:57 +00001039 if (output == NULL) return;
1040
Owen Taylor3473f882001-02-23 17:55:21 +00001041 for (i = 0;((i < depth) && (i < 25));i++)
1042 shift[2 * i] = shift[2 * i + 1] = ' ';
1043 shift[2 * i] = shift[2 * i + 1] = 0;
1044
Kasimier T. Buchcik97258712006-01-05 12:30:43 +00001045
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001046 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001047
1048 if (cur == NULL) {
1049 fprintf(output, "Object is empty (NULL)\n");
1050 return;
1051 }
1052 switch(cur->type) {
1053 case XPATH_UNDEFINED:
1054 fprintf(output, "Object is uninitialized\n");
1055 break;
1056 case XPATH_NODESET:
1057 fprintf(output, "Object is a Node Set :\n");
1058 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1059 break;
1060 case XPATH_XSLT_TREE:
1061 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001062 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +00001063 break;
1064 case XPATH_BOOLEAN:
1065 fprintf(output, "Object is a Boolean : ");
1066 if (cur->boolval) fprintf(output, "true\n");
1067 else fprintf(output, "false\n");
1068 break;
1069 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +00001070 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001071 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001072 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001073 break;
1074 case -1:
1075 fprintf(output, "Object is a number : -Infinity\n");
1076 break;
1077 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001078 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001079 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001080 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1081 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001082 } else {
1083 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1084 }
1085 }
Owen Taylor3473f882001-02-23 17:55:21 +00001086 break;
1087 case XPATH_STRING:
1088 fprintf(output, "Object is a string : ");
1089 xmlDebugDumpString(output, cur->stringval);
1090 fprintf(output, "\n");
1091 break;
1092 case XPATH_POINT:
1093 fprintf(output, "Object is a point : index %d in node", cur->index);
1094 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1095 fprintf(output, "\n");
1096 break;
1097 case XPATH_RANGE:
1098 if ((cur->user2 == NULL) ||
1099 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1100 fprintf(output, "Object is a collapsed range :\n");
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001101 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001102 if (cur->index >= 0)
1103 fprintf(output, "index %d in ", cur->index);
1104 fprintf(output, "node\n");
1105 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1106 depth + 1);
1107 } else {
1108 fprintf(output, "Object is a range :\n");
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001109 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001110 fprintf(output, "From ");
1111 if (cur->index >= 0)
1112 fprintf(output, "index %d in ", cur->index);
1113 fprintf(output, "node\n");
1114 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1115 depth + 1);
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001116 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001117 fprintf(output, "To ");
1118 if (cur->index2 >= 0)
1119 fprintf(output, "index %d in ", cur->index2);
1120 fprintf(output, "node\n");
1121 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1122 depth + 1);
1123 fprintf(output, "\n");
1124 }
1125 break;
1126 case XPATH_LOCATIONSET:
1127#if defined(LIBXML_XPTR_ENABLED)
1128 fprintf(output, "Object is a Location Set:\n");
1129 xmlXPathDebugDumpLocationSet(output,
1130 (xmlLocationSetPtr) cur->user, depth);
1131#endif
1132 break;
1133 case XPATH_USERS:
1134 fprintf(output, "Object is user defined\n");
1135 break;
1136 }
1137}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001138
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001139static void
1140xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001141 xmlXPathStepOpPtr op, int depth) {
1142 int i;
1143 char shift[100];
1144
1145 for (i = 0;((i < depth) && (i < 25));i++)
1146 shift[2 * i] = shift[2 * i + 1] = ' ';
1147 shift[2 * i] = shift[2 * i + 1] = 0;
1148
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001149 fprintf(output, "%s", shift);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001150 if (op == NULL) {
1151 fprintf(output, "Step is NULL\n");
1152 return;
1153 }
1154 switch (op->op) {
1155 case XPATH_OP_END:
1156 fprintf(output, "END"); break;
1157 case XPATH_OP_AND:
1158 fprintf(output, "AND"); break;
1159 case XPATH_OP_OR:
1160 fprintf(output, "OR"); break;
1161 case XPATH_OP_EQUAL:
1162 if (op->value)
1163 fprintf(output, "EQUAL =");
1164 else
1165 fprintf(output, "EQUAL !=");
1166 break;
1167 case XPATH_OP_CMP:
1168 if (op->value)
1169 fprintf(output, "CMP <");
1170 else
1171 fprintf(output, "CMP >");
1172 if (!op->value2)
1173 fprintf(output, "=");
1174 break;
1175 case XPATH_OP_PLUS:
1176 if (op->value == 0)
1177 fprintf(output, "PLUS -");
1178 else if (op->value == 1)
1179 fprintf(output, "PLUS +");
1180 else if (op->value == 2)
1181 fprintf(output, "PLUS unary -");
1182 else if (op->value == 3)
1183 fprintf(output, "PLUS unary - -");
1184 break;
1185 case XPATH_OP_MULT:
1186 if (op->value == 0)
1187 fprintf(output, "MULT *");
1188 else if (op->value == 1)
1189 fprintf(output, "MULT div");
1190 else
1191 fprintf(output, "MULT mod");
1192 break;
1193 case XPATH_OP_UNION:
1194 fprintf(output, "UNION"); break;
1195 case XPATH_OP_ROOT:
1196 fprintf(output, "ROOT"); break;
1197 case XPATH_OP_NODE:
1198 fprintf(output, "NODE"); break;
1199 case XPATH_OP_RESET:
1200 fprintf(output, "RESET"); break;
1201 case XPATH_OP_SORT:
1202 fprintf(output, "SORT"); break;
1203 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +00001204 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1205 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1206 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001207 const xmlChar *prefix = op->value4;
1208 const xmlChar *name = op->value5;
1209
1210 fprintf(output, "COLLECT ");
1211 switch (axis) {
1212 case AXIS_ANCESTOR:
1213 fprintf(output, " 'ancestors' "); break;
1214 case AXIS_ANCESTOR_OR_SELF:
1215 fprintf(output, " 'ancestors-or-self' "); break;
1216 case AXIS_ATTRIBUTE:
1217 fprintf(output, " 'attributes' "); break;
1218 case AXIS_CHILD:
1219 fprintf(output, " 'child' "); break;
1220 case AXIS_DESCENDANT:
1221 fprintf(output, " 'descendant' "); break;
1222 case AXIS_DESCENDANT_OR_SELF:
1223 fprintf(output, " 'descendant-or-self' "); break;
1224 case AXIS_FOLLOWING:
1225 fprintf(output, " 'following' "); break;
1226 case AXIS_FOLLOWING_SIBLING:
1227 fprintf(output, " 'following-siblings' "); break;
1228 case AXIS_NAMESPACE:
1229 fprintf(output, " 'namespace' "); break;
1230 case AXIS_PARENT:
1231 fprintf(output, " 'parent' "); break;
1232 case AXIS_PRECEDING:
1233 fprintf(output, " 'preceding' "); break;
1234 case AXIS_PRECEDING_SIBLING:
1235 fprintf(output, " 'preceding-sibling' "); break;
1236 case AXIS_SELF:
1237 fprintf(output, " 'self' "); break;
1238 }
1239 switch (test) {
1240 case NODE_TEST_NONE:
1241 fprintf(output, "'none' "); break;
1242 case NODE_TEST_TYPE:
1243 fprintf(output, "'type' "); break;
1244 case NODE_TEST_PI:
1245 fprintf(output, "'PI' "); break;
1246 case NODE_TEST_ALL:
1247 fprintf(output, "'all' "); break;
1248 case NODE_TEST_NS:
1249 fprintf(output, "'namespace' "); break;
1250 case NODE_TEST_NAME:
1251 fprintf(output, "'name' "); break;
1252 }
1253 switch (type) {
1254 case NODE_TYPE_NODE:
1255 fprintf(output, "'node' "); break;
1256 case NODE_TYPE_COMMENT:
1257 fprintf(output, "'comment' "); break;
1258 case NODE_TYPE_TEXT:
1259 fprintf(output, "'text' "); break;
1260 case NODE_TYPE_PI:
1261 fprintf(output, "'PI' "); break;
1262 }
1263 if (prefix != NULL)
1264 fprintf(output, "%s:", prefix);
1265 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001266 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001267 break;
1268
1269 }
1270 case XPATH_OP_VALUE: {
1271 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1272
1273 fprintf(output, "ELEM ");
1274 xmlXPathDebugDumpObject(output, object, 0);
1275 goto finish;
1276 }
1277 case XPATH_OP_VARIABLE: {
1278 const xmlChar *prefix = op->value5;
1279 const xmlChar *name = op->value4;
1280
1281 if (prefix != NULL)
1282 fprintf(output, "VARIABLE %s:%s", prefix, name);
1283 else
1284 fprintf(output, "VARIABLE %s", name);
1285 break;
1286 }
1287 case XPATH_OP_FUNCTION: {
1288 int nbargs = op->value;
1289 const xmlChar *prefix = op->value5;
1290 const xmlChar *name = op->value4;
1291
1292 if (prefix != NULL)
1293 fprintf(output, "FUNCTION %s:%s(%d args)",
1294 prefix, name, nbargs);
1295 else
1296 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1297 break;
1298 }
1299 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1300 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001301 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001302#ifdef LIBXML_XPTR_ENABLED
1303 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1304#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001305 default:
1306 fprintf(output, "UNKNOWN %d\n", op->op); return;
1307 }
1308 fprintf(output, "\n");
1309finish:
1310 if (op->ch1 >= 0)
1311 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1312 if (op->ch2 >= 0)
1313 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1314}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001315
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001316/**
1317 * xmlXPathDebugDumpCompExpr:
1318 * @output: the FILE * for the output
1319 * @comp: the precompiled XPath expression
1320 * @depth: the indentation level.
1321 *
1322 * Dumps the tree of the compiled XPath expression.
1323 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001324void
1325xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1326 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001327 int i;
1328 char shift[100];
1329
Daniel Veillarda82b1822004-11-08 16:24:57 +00001330 if ((output == NULL) || (comp == NULL)) return;
1331
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001332 for (i = 0;((i < depth) && (i < 25));i++)
1333 shift[2 * i] = shift[2 * i + 1] = ' ';
1334 shift[2 * i] = shift[2 * i + 1] = 0;
1335
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001336 fprintf(output, "%s", shift);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001337
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001338 fprintf(output, "Compiled Expression : %d elements\n",
1339 comp->nbStep);
1340 i = comp->last;
1341 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1342}
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001343
1344#ifdef XP_DEBUG_OBJ_USAGE
1345
1346/*
1347* XPath object usage related debugging variables.
1348*/
1349static int xmlXPathDebugObjCounterUndefined = 0;
1350static int xmlXPathDebugObjCounterNodeset = 0;
1351static int xmlXPathDebugObjCounterBool = 0;
1352static int xmlXPathDebugObjCounterNumber = 0;
1353static int xmlXPathDebugObjCounterString = 0;
1354static int xmlXPathDebugObjCounterPoint = 0;
1355static int xmlXPathDebugObjCounterRange = 0;
1356static int xmlXPathDebugObjCounterLocset = 0;
1357static int xmlXPathDebugObjCounterUsers = 0;
1358static int xmlXPathDebugObjCounterXSLTTree = 0;
1359static int xmlXPathDebugObjCounterAll = 0;
1360
1361static int xmlXPathDebugObjTotalUndefined = 0;
1362static int xmlXPathDebugObjTotalNodeset = 0;
1363static int xmlXPathDebugObjTotalBool = 0;
1364static int xmlXPathDebugObjTotalNumber = 0;
1365static int xmlXPathDebugObjTotalString = 0;
1366static int xmlXPathDebugObjTotalPoint = 0;
1367static int xmlXPathDebugObjTotalRange = 0;
1368static int xmlXPathDebugObjTotalLocset = 0;
1369static int xmlXPathDebugObjTotalUsers = 0;
1370static int xmlXPathDebugObjTotalXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001371static int xmlXPathDebugObjTotalAll = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001372
1373static int xmlXPathDebugObjMaxUndefined = 0;
1374static int xmlXPathDebugObjMaxNodeset = 0;
1375static int xmlXPathDebugObjMaxBool = 0;
1376static int xmlXPathDebugObjMaxNumber = 0;
1377static int xmlXPathDebugObjMaxString = 0;
1378static int xmlXPathDebugObjMaxPoint = 0;
1379static int xmlXPathDebugObjMaxRange = 0;
1380static int xmlXPathDebugObjMaxLocset = 0;
1381static int xmlXPathDebugObjMaxUsers = 0;
1382static int xmlXPathDebugObjMaxXSLTTree = 0;
1383static int xmlXPathDebugObjMaxAll = 0;
1384
1385/* REVISIT TODO: Make this static when committing */
1386static void
1387xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1388{
1389 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001390 if (ctxt->cache != NULL) {
1391 xmlXPathContextCachePtr cache =
1392 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001393
1394 cache->dbgCachedAll = 0;
1395 cache->dbgCachedNodeset = 0;
1396 cache->dbgCachedString = 0;
1397 cache->dbgCachedBool = 0;
1398 cache->dbgCachedNumber = 0;
1399 cache->dbgCachedPoint = 0;
1400 cache->dbgCachedRange = 0;
1401 cache->dbgCachedLocset = 0;
1402 cache->dbgCachedUsers = 0;
1403 cache->dbgCachedXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001404 cache->dbgCachedUndefined = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001405
1406 cache->dbgReusedAll = 0;
1407 cache->dbgReusedNodeset = 0;
1408 cache->dbgReusedString = 0;
1409 cache->dbgReusedBool = 0;
1410 cache->dbgReusedNumber = 0;
1411 cache->dbgReusedPoint = 0;
1412 cache->dbgReusedRange = 0;
1413 cache->dbgReusedLocset = 0;
1414 cache->dbgReusedUsers = 0;
1415 cache->dbgReusedXSLTTree = 0;
1416 cache->dbgReusedUndefined = 0;
1417 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00001418 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001419
1420 xmlXPathDebugObjCounterUndefined = 0;
1421 xmlXPathDebugObjCounterNodeset = 0;
1422 xmlXPathDebugObjCounterBool = 0;
1423 xmlXPathDebugObjCounterNumber = 0;
1424 xmlXPathDebugObjCounterString = 0;
1425 xmlXPathDebugObjCounterPoint = 0;
1426 xmlXPathDebugObjCounterRange = 0;
1427 xmlXPathDebugObjCounterLocset = 0;
1428 xmlXPathDebugObjCounterUsers = 0;
1429 xmlXPathDebugObjCounterXSLTTree = 0;
1430 xmlXPathDebugObjCounterAll = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001431
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001432 xmlXPathDebugObjTotalUndefined = 0;
1433 xmlXPathDebugObjTotalNodeset = 0;
1434 xmlXPathDebugObjTotalBool = 0;
1435 xmlXPathDebugObjTotalNumber = 0;
1436 xmlXPathDebugObjTotalString = 0;
1437 xmlXPathDebugObjTotalPoint = 0;
1438 xmlXPathDebugObjTotalRange = 0;
1439 xmlXPathDebugObjTotalLocset = 0;
1440 xmlXPathDebugObjTotalUsers = 0;
1441 xmlXPathDebugObjTotalXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001442 xmlXPathDebugObjTotalAll = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001443
1444 xmlXPathDebugObjMaxUndefined = 0;
1445 xmlXPathDebugObjMaxNodeset = 0;
1446 xmlXPathDebugObjMaxBool = 0;
1447 xmlXPathDebugObjMaxNumber = 0;
1448 xmlXPathDebugObjMaxString = 0;
1449 xmlXPathDebugObjMaxPoint = 0;
1450 xmlXPathDebugObjMaxRange = 0;
1451 xmlXPathDebugObjMaxLocset = 0;
1452 xmlXPathDebugObjMaxUsers = 0;
1453 xmlXPathDebugObjMaxXSLTTree = 0;
1454 xmlXPathDebugObjMaxAll = 0;
1455
1456}
1457
1458static void
1459xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1460 xmlXPathObjectType objType)
1461{
1462 int isCached = 0;
1463
1464 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001465 if (ctxt->cache != NULL) {
1466 xmlXPathContextCachePtr cache =
1467 (xmlXPathContextCachePtr) ctxt->cache;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001468
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001469 isCached = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001470
1471 cache->dbgReusedAll++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001472 switch (objType) {
1473 case XPATH_UNDEFINED:
1474 cache->dbgReusedUndefined++;
1475 break;
1476 case XPATH_NODESET:
1477 cache->dbgReusedNodeset++;
1478 break;
1479 case XPATH_BOOLEAN:
1480 cache->dbgReusedBool++;
1481 break;
1482 case XPATH_NUMBER:
1483 cache->dbgReusedNumber++;
1484 break;
1485 case XPATH_STRING:
1486 cache->dbgReusedString++;
1487 break;
1488 case XPATH_POINT:
1489 cache->dbgReusedPoint++;
1490 break;
1491 case XPATH_RANGE:
1492 cache->dbgReusedRange++;
1493 break;
1494 case XPATH_LOCATIONSET:
1495 cache->dbgReusedLocset++;
1496 break;
1497 case XPATH_USERS:
1498 cache->dbgReusedUsers++;
1499 break;
1500 case XPATH_XSLT_TREE:
1501 cache->dbgReusedXSLTTree++;
1502 break;
1503 default:
1504 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001505 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001506 }
1507 }
1508
1509 switch (objType) {
1510 case XPATH_UNDEFINED:
1511 if (! isCached)
1512 xmlXPathDebugObjTotalUndefined++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001513 xmlXPathDebugObjCounterUndefined++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001514 if (xmlXPathDebugObjCounterUndefined >
1515 xmlXPathDebugObjMaxUndefined)
1516 xmlXPathDebugObjMaxUndefined =
1517 xmlXPathDebugObjCounterUndefined;
1518 break;
1519 case XPATH_NODESET:
1520 if (! isCached)
1521 xmlXPathDebugObjTotalNodeset++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001522 xmlXPathDebugObjCounterNodeset++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001523 if (xmlXPathDebugObjCounterNodeset >
1524 xmlXPathDebugObjMaxNodeset)
1525 xmlXPathDebugObjMaxNodeset =
1526 xmlXPathDebugObjCounterNodeset;
1527 break;
1528 case XPATH_BOOLEAN:
1529 if (! isCached)
1530 xmlXPathDebugObjTotalBool++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001531 xmlXPathDebugObjCounterBool++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001532 if (xmlXPathDebugObjCounterBool >
1533 xmlXPathDebugObjMaxBool)
1534 xmlXPathDebugObjMaxBool =
1535 xmlXPathDebugObjCounterBool;
1536 break;
1537 case XPATH_NUMBER:
1538 if (! isCached)
1539 xmlXPathDebugObjTotalNumber++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001540 xmlXPathDebugObjCounterNumber++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001541 if (xmlXPathDebugObjCounterNumber >
1542 xmlXPathDebugObjMaxNumber)
1543 xmlXPathDebugObjMaxNumber =
1544 xmlXPathDebugObjCounterNumber;
1545 break;
1546 case XPATH_STRING:
1547 if (! isCached)
1548 xmlXPathDebugObjTotalString++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001549 xmlXPathDebugObjCounterString++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001550 if (xmlXPathDebugObjCounterString >
1551 xmlXPathDebugObjMaxString)
1552 xmlXPathDebugObjMaxString =
1553 xmlXPathDebugObjCounterString;
1554 break;
1555 case XPATH_POINT:
1556 if (! isCached)
1557 xmlXPathDebugObjTotalPoint++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001558 xmlXPathDebugObjCounterPoint++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001559 if (xmlXPathDebugObjCounterPoint >
1560 xmlXPathDebugObjMaxPoint)
1561 xmlXPathDebugObjMaxPoint =
1562 xmlXPathDebugObjCounterPoint;
1563 break;
1564 case XPATH_RANGE:
1565 if (! isCached)
1566 xmlXPathDebugObjTotalRange++;
1567 xmlXPathDebugObjCounterRange++;
1568 if (xmlXPathDebugObjCounterRange >
1569 xmlXPathDebugObjMaxRange)
1570 xmlXPathDebugObjMaxRange =
1571 xmlXPathDebugObjCounterRange;
1572 break;
1573 case XPATH_LOCATIONSET:
1574 if (! isCached)
1575 xmlXPathDebugObjTotalLocset++;
1576 xmlXPathDebugObjCounterLocset++;
1577 if (xmlXPathDebugObjCounterLocset >
1578 xmlXPathDebugObjMaxLocset)
1579 xmlXPathDebugObjMaxLocset =
1580 xmlXPathDebugObjCounterLocset;
1581 break;
1582 case XPATH_USERS:
1583 if (! isCached)
1584 xmlXPathDebugObjTotalUsers++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001585 xmlXPathDebugObjCounterUsers++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001586 if (xmlXPathDebugObjCounterUsers >
1587 xmlXPathDebugObjMaxUsers)
1588 xmlXPathDebugObjMaxUsers =
1589 xmlXPathDebugObjCounterUsers;
1590 break;
1591 case XPATH_XSLT_TREE:
1592 if (! isCached)
1593 xmlXPathDebugObjTotalXSLTTree++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001594 xmlXPathDebugObjCounterXSLTTree++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001595 if (xmlXPathDebugObjCounterXSLTTree >
1596 xmlXPathDebugObjMaxXSLTTree)
1597 xmlXPathDebugObjMaxXSLTTree =
1598 xmlXPathDebugObjCounterXSLTTree;
1599 break;
1600 default:
1601 break;
1602 }
1603 if (! isCached)
1604 xmlXPathDebugObjTotalAll++;
1605 xmlXPathDebugObjCounterAll++;
1606 if (xmlXPathDebugObjCounterAll >
1607 xmlXPathDebugObjMaxAll)
1608 xmlXPathDebugObjMaxAll =
1609 xmlXPathDebugObjCounterAll;
1610}
1611
1612static void
1613xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1614 xmlXPathObjectType objType)
1615{
1616 int isCached = 0;
1617
1618 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001619 if (ctxt->cache != NULL) {
1620 xmlXPathContextCachePtr cache =
1621 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001622
Daniel Veillard45490ae2008-07-29 09:13:19 +00001623 isCached = 1;
1624
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001625 cache->dbgCachedAll++;
1626 switch (objType) {
1627 case XPATH_UNDEFINED:
1628 cache->dbgCachedUndefined++;
1629 break;
1630 case XPATH_NODESET:
1631 cache->dbgCachedNodeset++;
1632 break;
1633 case XPATH_BOOLEAN:
1634 cache->dbgCachedBool++;
1635 break;
1636 case XPATH_NUMBER:
1637 cache->dbgCachedNumber++;
1638 break;
1639 case XPATH_STRING:
1640 cache->dbgCachedString++;
1641 break;
1642 case XPATH_POINT:
1643 cache->dbgCachedPoint++;
1644 break;
1645 case XPATH_RANGE:
1646 cache->dbgCachedRange++;
1647 break;
1648 case XPATH_LOCATIONSET:
1649 cache->dbgCachedLocset++;
1650 break;
1651 case XPATH_USERS:
1652 cache->dbgCachedUsers++;
1653 break;
1654 case XPATH_XSLT_TREE:
1655 cache->dbgCachedXSLTTree++;
1656 break;
1657 default:
1658 break;
1659 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00001660
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001661 }
1662 }
1663 switch (objType) {
1664 case XPATH_UNDEFINED:
1665 xmlXPathDebugObjCounterUndefined--;
1666 break;
1667 case XPATH_NODESET:
1668 xmlXPathDebugObjCounterNodeset--;
1669 break;
1670 case XPATH_BOOLEAN:
1671 xmlXPathDebugObjCounterBool--;
1672 break;
1673 case XPATH_NUMBER:
1674 xmlXPathDebugObjCounterNumber--;
1675 break;
1676 case XPATH_STRING:
1677 xmlXPathDebugObjCounterString--;
1678 break;
1679 case XPATH_POINT:
1680 xmlXPathDebugObjCounterPoint--;
1681 break;
1682 case XPATH_RANGE:
1683 xmlXPathDebugObjCounterRange--;
1684 break;
1685 case XPATH_LOCATIONSET:
1686 xmlXPathDebugObjCounterLocset--;
1687 break;
1688 case XPATH_USERS:
1689 xmlXPathDebugObjCounterUsers--;
1690 break;
1691 case XPATH_XSLT_TREE:
1692 xmlXPathDebugObjCounterXSLTTree--;
1693 break;
1694 default:
1695 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001696 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001697 xmlXPathDebugObjCounterAll--;
1698}
1699
1700/* REVISIT TODO: Make this static when committing */
1701static void
1702xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
1703{
1704 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
1705 reqXSLTTree, reqUndefined;
1706 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
1707 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
1708 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
1709 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
1710 int leftObjs = xmlXPathDebugObjCounterAll;
1711
1712 reqAll = xmlXPathDebugObjTotalAll;
1713 reqNodeset = xmlXPathDebugObjTotalNodeset;
1714 reqString = xmlXPathDebugObjTotalString;
1715 reqBool = xmlXPathDebugObjTotalBool;
1716 reqNumber = xmlXPathDebugObjTotalNumber;
1717 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
1718 reqUndefined = xmlXPathDebugObjTotalUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001719
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001720 printf("# XPath object usage:\n");
1721
1722 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001723 if (ctxt->cache != NULL) {
1724 xmlXPathContextCachePtr cache =
1725 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001726
1727 reAll = cache->dbgReusedAll;
1728 reqAll += reAll;
1729 reNodeset = cache->dbgReusedNodeset;
1730 reqNodeset += reNodeset;
1731 reString = cache->dbgReusedString;
1732 reqString += reString;
1733 reBool = cache->dbgReusedBool;
1734 reqBool += reBool;
1735 reNumber = cache->dbgReusedNumber;
1736 reqNumber += reNumber;
1737 reXSLTTree = cache->dbgReusedXSLTTree;
1738 reqXSLTTree += reXSLTTree;
1739 reUndefined = cache->dbgReusedUndefined;
1740 reqUndefined += reUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001741
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001742 caAll = cache->dbgCachedAll;
1743 caBool = cache->dbgCachedBool;
1744 caNodeset = cache->dbgCachedNodeset;
1745 caString = cache->dbgCachedString;
1746 caNumber = cache->dbgCachedNumber;
1747 caXSLTTree = cache->dbgCachedXSLTTree;
1748 caUndefined = cache->dbgCachedUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001749
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001750 if (cache->nodesetObjs)
1751 leftObjs -= cache->nodesetObjs->number;
1752 if (cache->stringObjs)
1753 leftObjs -= cache->stringObjs->number;
1754 if (cache->booleanObjs)
1755 leftObjs -= cache->booleanObjs->number;
1756 if (cache->numberObjs)
1757 leftObjs -= cache->numberObjs->number;
1758 if (cache->miscObjs)
1759 leftObjs -= cache->miscObjs->number;
1760 }
1761 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00001762
1763 printf("# all\n");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001764 printf("# total : %d\n", reqAll);
1765 printf("# left : %d\n", leftObjs);
1766 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
1767 printf("# reused : %d\n", reAll);
1768 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
1769
1770 printf("# node-sets\n");
1771 printf("# total : %d\n", reqNodeset);
1772 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
1773 printf("# reused : %d\n", reNodeset);
1774 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
1775
1776 printf("# strings\n");
1777 printf("# total : %d\n", reqString);
1778 printf("# created: %d\n", xmlXPathDebugObjTotalString);
1779 printf("# reused : %d\n", reString);
1780 printf("# max : %d\n", xmlXPathDebugObjMaxString);
1781
1782 printf("# booleans\n");
1783 printf("# total : %d\n", reqBool);
1784 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
1785 printf("# reused : %d\n", reBool);
1786 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
1787
1788 printf("# numbers\n");
1789 printf("# total : %d\n", reqNumber);
1790 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
1791 printf("# reused : %d\n", reNumber);
1792 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
1793
1794 printf("# XSLT result tree fragments\n");
1795 printf("# total : %d\n", reqXSLTTree);
1796 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
1797 printf("# reused : %d\n", reXSLTTree);
1798 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
1799
1800 printf("# undefined\n");
1801 printf("# total : %d\n", reqUndefined);
1802 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
1803 printf("# reused : %d\n", reUndefined);
1804 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
1805
1806}
1807
1808#endif /* XP_DEBUG_OBJ_USAGE */
1809
Daniel Veillard017b1082001-06-21 11:20:21 +00001810#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001811
1812/************************************************************************
1813 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001814 * XPath object caching *
1815 * *
1816 ************************************************************************/
1817
1818/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001819 * xmlXPathNewCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001820 *
1821 * Create a new object cache
1822 *
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001823 * Returns the xmlXPathCache just allocated.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001824 */
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001825static xmlXPathContextCachePtr
1826xmlXPathNewCache(void)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001827{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001828 xmlXPathContextCachePtr ret;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001829
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001830 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001831 if (ret == NULL) {
1832 xmlXPathErrMemory(NULL, "creating object cache\n");
1833 return(NULL);
1834 }
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001835 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001836 ret->maxNodeset = 100;
1837 ret->maxString = 100;
1838 ret->maxBoolean = 100;
1839 ret->maxNumber = 100;
1840 ret->maxMisc = 100;
1841 return(ret);
1842}
1843
1844static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001845xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001846{
1847 int i;
1848 xmlXPathObjectPtr obj;
1849
1850 if (list == NULL)
1851 return;
1852
1853 for (i = 0; i < list->number; i++) {
1854 obj = list->items[i];
1855 /*
1856 * Note that it is already assured that we don't need to
1857 * look out for namespace nodes in the node-set.
1858 */
1859 if (obj->nodesetval != NULL) {
1860 if (obj->nodesetval->nodeTab != NULL)
1861 xmlFree(obj->nodesetval->nodeTab);
1862 xmlFree(obj->nodesetval);
1863 }
1864 xmlFree(obj);
1865#ifdef XP_DEBUG_OBJ_USAGE
1866 xmlXPathDebugObjCounterAll--;
1867#endif
1868 }
1869 xmlPointerListFree(list);
1870}
1871
1872static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001873xmlXPathFreeCache(xmlXPathContextCachePtr cache)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001874{
1875 if (cache == NULL)
1876 return;
1877 if (cache->nodesetObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001878 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001879 if (cache->stringObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001880 xmlXPathCacheFreeObjectList(cache->stringObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001881 if (cache->booleanObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001882 xmlXPathCacheFreeObjectList(cache->booleanObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001883 if (cache->numberObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001884 xmlXPathCacheFreeObjectList(cache->numberObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001885 if (cache->miscObjs)
Daniel Veillard45490ae2008-07-29 09:13:19 +00001886 xmlXPathCacheFreeObjectList(cache->miscObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001887 xmlFree(cache);
1888}
1889
1890/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001891 * xmlXPathContextSetCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001892 *
1893 * @ctxt: the XPath context
1894 * @active: enables/disables (creates/frees) the cache
Daniel Veillard45490ae2008-07-29 09:13:19 +00001895 * @value: a value with semantics dependant on @options
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001896 * @options: options (currently only the value 0 is used)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001897 *
1898 * Creates/frees an object cache on the XPath context.
1899 * If activates XPath objects (xmlXPathObject) will be cached internally
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001900 * to be reused.
1901 * @options:
1902 * 0: This will set the XPath object caching:
1903 * @value:
1904 * This will set the maximum number of XPath objects
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001905 * to be cached per slot
1906 * There are 5 slots for: node-set, string, number, boolean, and
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001907 * misc objects. Use <0 for the default number (100).
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001908 * Other values for @options have currently no effect.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001909 *
1910 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1911 */
1912int
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001913xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1914 int active,
1915 int value,
1916 int options)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001917{
1918 if (ctxt == NULL)
1919 return(-1);
1920 if (active) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001921 xmlXPathContextCachePtr cache;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001922
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001923 if (ctxt->cache == NULL) {
1924 ctxt->cache = xmlXPathNewCache();
1925 if (ctxt->cache == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001926 return(-1);
1927 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001928 cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001929 if (options == 0) {
1930 if (value < 0)
1931 value = 100;
1932 cache->maxNodeset = value;
1933 cache->maxString = value;
1934 cache->maxNumber = value;
1935 cache->maxBoolean = value;
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001936 cache->maxMisc = value;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001937 }
1938 } else if (ctxt->cache != NULL) {
1939 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1940 ctxt->cache = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001941 }
1942 return(0);
1943}
1944
1945/**
1946 * xmlXPathCacheWrapNodeSet:
1947 * @ctxt: the XPath context
1948 * @val: the NodePtr value
1949 *
1950 * This is the cached version of xmlXPathWrapNodeSet().
1951 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1952 *
1953 * Returns the created or reused object.
1954 */
1955static xmlXPathObjectPtr
1956xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00001957{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001958 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1959 xmlXPathContextCachePtr cache =
1960 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001961
1962 if ((cache->miscObjs != NULL) &&
1963 (cache->miscObjs->number != 0))
1964 {
1965 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001966
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001967 ret = (xmlXPathObjectPtr)
1968 cache->miscObjs->items[--cache->miscObjs->number];
1969 ret->type = XPATH_NODESET;
1970 ret->nodesetval = val;
1971#ifdef XP_DEBUG_OBJ_USAGE
1972 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
1973#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00001974 return(ret);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001975 }
1976 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00001977
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001978 return(xmlXPathWrapNodeSet(val));
Daniel Veillard45490ae2008-07-29 09:13:19 +00001979
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001980}
1981
1982/**
1983 * xmlXPathCacheWrapString:
1984 * @ctxt: the XPath context
1985 * @val: the xmlChar * value
1986 *
1987 * This is the cached version of xmlXPathWrapString().
1988 * Wraps the @val string into an XPath object.
1989 *
1990 * Returns the created or reused object.
1991 */
1992static xmlXPathObjectPtr
1993xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00001994{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001995 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1996 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001997
1998 if ((cache->stringObjs != NULL) &&
1999 (cache->stringObjs->number != 0))
2000 {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002001
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002002 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002003
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002004 ret = (xmlXPathObjectPtr)
2005 cache->stringObjs->items[--cache->stringObjs->number];
2006 ret->type = XPATH_STRING;
2007 ret->stringval = val;
2008#ifdef XP_DEBUG_OBJ_USAGE
2009 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2010#endif
2011 return(ret);
2012 } else if ((cache->miscObjs != NULL) &&
2013 (cache->miscObjs->number != 0))
2014 {
2015 xmlXPathObjectPtr ret;
2016 /*
2017 * Fallback to misc-cache.
2018 */
2019 ret = (xmlXPathObjectPtr)
2020 cache->miscObjs->items[--cache->miscObjs->number];
2021
2022 ret->type = XPATH_STRING;
2023 ret->stringval = val;
2024#ifdef XP_DEBUG_OBJ_USAGE
2025 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2026#endif
2027 return(ret);
2028 }
2029 }
2030 return(xmlXPathWrapString(val));
2031}
2032
2033/**
2034 * xmlXPathCacheNewNodeSet:
2035 * @ctxt: the XPath context
2036 * @val: the NodePtr value
2037 *
2038 * This is the cached version of xmlXPathNewNodeSet().
2039 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2040 * it with the single Node @val
2041 *
2042 * Returns the created or reused object.
2043 */
2044static xmlXPathObjectPtr
2045xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2046{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002047 if ((ctxt != NULL) && (ctxt->cache)) {
2048 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002049
2050 if ((cache->nodesetObjs != NULL) &&
2051 (cache->nodesetObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002052 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002053 xmlXPathObjectPtr ret;
2054 /*
2055 * Use the nodset-cache.
Daniel Veillard45490ae2008-07-29 09:13:19 +00002056 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002057 ret = (xmlXPathObjectPtr)
2058 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2059 ret->type = XPATH_NODESET;
2060 ret->boolval = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002061 if (val) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002062 if ((ret->nodesetval->nodeMax == 0) ||
2063 (val->type == XML_NAMESPACE_DECL))
2064 {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002065 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002066 } else {
2067 ret->nodesetval->nodeTab[0] = val;
2068 ret->nodesetval->nodeNr = 1;
2069 }
2070 }
2071#ifdef XP_DEBUG_OBJ_USAGE
2072 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2073#endif
2074 return(ret);
2075 } else if ((cache->miscObjs != NULL) &&
2076 (cache->miscObjs->number != 0))
2077 {
2078 xmlXPathObjectPtr ret;
2079 /*
2080 * Fallback to misc-cache.
2081 */
2082
2083 ret = (xmlXPathObjectPtr)
2084 cache->miscObjs->items[--cache->miscObjs->number];
2085
2086 ret->type = XPATH_NODESET;
2087 ret->boolval = 0;
2088 ret->nodesetval = xmlXPathNodeSetCreate(val);
2089#ifdef XP_DEBUG_OBJ_USAGE
2090 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2091#endif
2092 return(ret);
2093 }
2094 }
2095 return(xmlXPathNewNodeSet(val));
2096}
2097
2098/**
2099 * xmlXPathCacheNewCString:
2100 * @ctxt: the XPath context
2101 * @val: the char * value
2102 *
2103 * This is the cached version of xmlXPathNewCString().
2104 * Acquire an xmlXPathObjectPtr of type string and of value @val
2105 *
2106 * Returns the created or reused object.
2107 */
2108static xmlXPathObjectPtr
2109xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002110{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002111 if ((ctxt != NULL) && (ctxt->cache)) {
2112 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002113
2114 if ((cache->stringObjs != NULL) &&
2115 (cache->stringObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002116 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002117 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002118
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002119 ret = (xmlXPathObjectPtr)
2120 cache->stringObjs->items[--cache->stringObjs->number];
2121
2122 ret->type = XPATH_STRING;
2123 ret->stringval = xmlStrdup(BAD_CAST val);
2124#ifdef XP_DEBUG_OBJ_USAGE
2125 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2126#endif
2127 return(ret);
2128 } else if ((cache->miscObjs != NULL) &&
2129 (cache->miscObjs->number != 0))
2130 {
2131 xmlXPathObjectPtr ret;
2132
2133 ret = (xmlXPathObjectPtr)
2134 cache->miscObjs->items[--cache->miscObjs->number];
2135
2136 ret->type = XPATH_STRING;
2137 ret->stringval = xmlStrdup(BAD_CAST val);
2138#ifdef XP_DEBUG_OBJ_USAGE
2139 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2140#endif
2141 return(ret);
2142 }
2143 }
2144 return(xmlXPathNewCString(val));
2145}
2146
2147/**
2148 * xmlXPathCacheNewString:
2149 * @ctxt: the XPath context
2150 * @val: the xmlChar * value
2151 *
2152 * This is the cached version of xmlXPathNewString().
2153 * Acquire an xmlXPathObjectPtr of type string and of value @val
2154 *
2155 * Returns the created or reused object.
2156 */
2157static xmlXPathObjectPtr
2158xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002159{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002160 if ((ctxt != NULL) && (ctxt->cache)) {
2161 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002162
2163 if ((cache->stringObjs != NULL) &&
2164 (cache->stringObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002165 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002166 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002167
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002168 ret = (xmlXPathObjectPtr)
2169 cache->stringObjs->items[--cache->stringObjs->number];
2170 ret->type = XPATH_STRING;
2171 if (val != NULL)
2172 ret->stringval = xmlStrdup(val);
2173 else
2174 ret->stringval = xmlStrdup((const xmlChar *)"");
2175#ifdef XP_DEBUG_OBJ_USAGE
2176 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2177#endif
2178 return(ret);
2179 } else if ((cache->miscObjs != NULL) &&
2180 (cache->miscObjs->number != 0))
2181 {
2182 xmlXPathObjectPtr ret;
2183
2184 ret = (xmlXPathObjectPtr)
2185 cache->miscObjs->items[--cache->miscObjs->number];
2186
2187 ret->type = XPATH_STRING;
2188 if (val != NULL)
2189 ret->stringval = xmlStrdup(val);
2190 else
2191 ret->stringval = xmlStrdup((const xmlChar *)"");
2192#ifdef XP_DEBUG_OBJ_USAGE
2193 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2194#endif
2195 return(ret);
2196 }
2197 }
2198 return(xmlXPathNewString(val));
2199}
2200
2201/**
2202 * xmlXPathCacheNewBoolean:
2203 * @ctxt: the XPath context
2204 * @val: the boolean value
2205 *
2206 * This is the cached version of xmlXPathNewBoolean().
2207 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2208 *
2209 * Returns the created or reused object.
2210 */
2211static xmlXPathObjectPtr
2212xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002213{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002214 if ((ctxt != NULL) && (ctxt->cache)) {
2215 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002216
2217 if ((cache->booleanObjs != NULL) &&
2218 (cache->booleanObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002219 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002220 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002221
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002222 ret = (xmlXPathObjectPtr)
2223 cache->booleanObjs->items[--cache->booleanObjs->number];
2224 ret->type = XPATH_BOOLEAN;
2225 ret->boolval = (val != 0);
2226#ifdef XP_DEBUG_OBJ_USAGE
2227 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2228#endif
2229 return(ret);
2230 } else if ((cache->miscObjs != NULL) &&
2231 (cache->miscObjs->number != 0))
2232 {
2233 xmlXPathObjectPtr ret;
2234
2235 ret = (xmlXPathObjectPtr)
2236 cache->miscObjs->items[--cache->miscObjs->number];
2237
2238 ret->type = XPATH_BOOLEAN;
2239 ret->boolval = (val != 0);
2240#ifdef XP_DEBUG_OBJ_USAGE
2241 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2242#endif
2243 return(ret);
2244 }
2245 }
2246 return(xmlXPathNewBoolean(val));
2247}
2248
2249/**
2250 * xmlXPathCacheNewFloat:
2251 * @ctxt: the XPath context
2252 * @val: the double value
2253 *
2254 * This is the cached version of xmlXPathNewFloat().
2255 * Acquires an xmlXPathObjectPtr of type double and of value @val
2256 *
2257 * Returns the created or reused object.
2258 */
2259static xmlXPathObjectPtr
2260xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2261{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002262 if ((ctxt != NULL) && (ctxt->cache)) {
2263 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002264
2265 if ((cache->numberObjs != NULL) &&
2266 (cache->numberObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002267 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002268 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002269
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002270 ret = (xmlXPathObjectPtr)
2271 cache->numberObjs->items[--cache->numberObjs->number];
2272 ret->type = XPATH_NUMBER;
2273 ret->floatval = val;
2274#ifdef XP_DEBUG_OBJ_USAGE
2275 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2276#endif
2277 return(ret);
2278 } else if ((cache->miscObjs != NULL) &&
2279 (cache->miscObjs->number != 0))
2280 {
2281 xmlXPathObjectPtr ret;
2282
2283 ret = (xmlXPathObjectPtr)
2284 cache->miscObjs->items[--cache->miscObjs->number];
2285
2286 ret->type = XPATH_NUMBER;
2287 ret->floatval = val;
2288#ifdef XP_DEBUG_OBJ_USAGE
2289 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2290#endif
2291 return(ret);
2292 }
2293 }
2294 return(xmlXPathNewFloat(val));
2295}
2296
2297/**
2298 * xmlXPathCacheConvertString:
2299 * @ctxt: the XPath context
2300 * @val: an XPath object
2301 *
2302 * This is the cached version of xmlXPathConvertString().
2303 * Converts an existing object to its string() equivalent
2304 *
2305 * Returns a created or reused object, the old one is freed (cached)
2306 * (or the operation is done directly on @val)
2307 */
2308
2309static xmlXPathObjectPtr
2310xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002311 xmlChar *res = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002312
2313 if (val == NULL)
2314 return(xmlXPathCacheNewCString(ctxt, ""));
2315
2316 switch (val->type) {
2317 case XPATH_UNDEFINED:
2318#ifdef DEBUG_EXPR
2319 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2320#endif
2321 break;
2322 case XPATH_NODESET:
2323 case XPATH_XSLT_TREE:
2324 res = xmlXPathCastNodeSetToString(val->nodesetval);
2325 break;
2326 case XPATH_STRING:
2327 return(val);
2328 case XPATH_BOOLEAN:
2329 res = xmlXPathCastBooleanToString(val->boolval);
2330 break;
2331 case XPATH_NUMBER:
2332 res = xmlXPathCastNumberToString(val->floatval);
2333 break;
2334 case XPATH_USERS:
2335 case XPATH_POINT:
2336 case XPATH_RANGE:
2337 case XPATH_LOCATIONSET:
2338 TODO;
2339 break;
2340 }
2341 xmlXPathReleaseObject(ctxt, val);
2342 if (res == NULL)
2343 return(xmlXPathCacheNewCString(ctxt, ""));
2344 return(xmlXPathCacheWrapString(ctxt, res));
2345}
2346
2347/**
2348 * xmlXPathCacheObjectCopy:
2349 * @ctxt: the XPath context
2350 * @val: the original object
2351 *
2352 * This is the cached version of xmlXPathObjectCopy().
2353 * Acquire a copy of a given object
2354 *
2355 * Returns a created or reused created object.
2356 */
2357static xmlXPathObjectPtr
2358xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2359{
2360 if (val == NULL)
2361 return(NULL);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002362
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002363 if (XP_HAS_CACHE(ctxt)) {
2364 switch (val->type) {
2365 case XPATH_NODESET:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002366 return(xmlXPathCacheWrapNodeSet(ctxt,
2367 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002368 case XPATH_STRING:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002369 return(xmlXPathCacheNewString(ctxt, val->stringval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002370 case XPATH_BOOLEAN:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002371 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002372 case XPATH_NUMBER:
2373 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2374 default:
2375 break;
2376 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002377 }
2378 return(xmlXPathObjectCopy(val));
2379}
2380
2381/**
2382 * xmlXPathCacheConvertBoolean:
2383 * @ctxt: the XPath context
2384 * @val: an XPath object
2385 *
2386 * This is the cached version of xmlXPathConvertBoolean().
2387 * Converts an existing object to its boolean() equivalent
2388 *
2389 * Returns a created or reused object, the old one is freed (or the operation
2390 * is done directly on @val)
2391 */
2392static xmlXPathObjectPtr
2393xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2394 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002395
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002396 if (val == NULL)
2397 return(xmlXPathCacheNewBoolean(ctxt, 0));
2398 if (val->type == XPATH_BOOLEAN)
2399 return(val);
2400 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2401 xmlXPathReleaseObject(ctxt, val);
2402 return(ret);
2403}
2404
2405/**
2406 * xmlXPathCacheConvertNumber:
2407 * @ctxt: the XPath context
2408 * @val: an XPath object
2409 *
2410 * This is the cached version of xmlXPathConvertNumber().
2411 * Converts an existing object to its number() equivalent
2412 *
2413 * Returns a created or reused object, the old one is freed (or the operation
2414 * is done directly on @val)
2415 */
2416static xmlXPathObjectPtr
2417xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2418 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002419
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002420 if (val == NULL)
2421 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2422 if (val->type == XPATH_NUMBER)
2423 return(val);
2424 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2425 xmlXPathReleaseObject(ctxt, val);
2426 return(ret);
2427}
2428
2429/************************************************************************
2430 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +00002431 * Parser stacks related functions and macros *
Owen Taylor3473f882001-02-23 17:55:21 +00002432 * *
2433 ************************************************************************/
2434
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002435/**
Daniel Veillardf5048b32011-08-18 17:10:13 +08002436 * xmlXPathSetFrame:
2437 * @ctxt: an XPath parser context
2438 *
2439 * Set the callee evaluation frame
2440 *
2441 * Returns the previous frame value to be restored once done
2442 */
2443static int
2444xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2445 int ret;
2446
2447 if (ctxt == NULL)
2448 return(0);
2449 ret = ctxt->valueFrame;
2450 ctxt->valueFrame = ctxt->valueNr;
2451 return(ret);
2452}
2453
2454/**
2455 * xmlXPathPopFrame:
2456 * @ctxt: an XPath parser context
2457 * @frame: the previous frame value
2458 *
2459 * Remove the callee evaluation frame
2460 */
2461static void
2462xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2463 if (ctxt == NULL)
2464 return;
2465 if (ctxt->valueNr < ctxt->valueFrame) {
2466 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2467 }
2468 ctxt->valueFrame = frame;
2469}
2470
2471/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002472 * valuePop:
2473 * @ctxt: an XPath evaluation context
2474 *
2475 * Pops the top XPath object from the value stack
2476 *
2477 * Returns the XPath object just removed
2478 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002479xmlXPathObjectPtr
Daniel Veillard1c732d22002-11-30 11:22:59 +00002480valuePop(xmlXPathParserContextPtr ctxt)
2481{
2482 xmlXPathObjectPtr ret;
2483
Daniel Veillarda82b1822004-11-08 16:24:57 +00002484 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
Daniel Veillard24505b02005-07-28 23:49:35 +00002485 return (NULL);
Daniel Veillardf5048b32011-08-18 17:10:13 +08002486
2487 if (ctxt->valueNr <= ctxt->valueFrame) {
2488 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2489 return (NULL);
2490 }
2491
Daniel Veillard1c732d22002-11-30 11:22:59 +00002492 ctxt->valueNr--;
2493 if (ctxt->valueNr > 0)
2494 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2495 else
2496 ctxt->value = NULL;
2497 ret = ctxt->valueTab[ctxt->valueNr];
Daniel Veillard24505b02005-07-28 23:49:35 +00002498 ctxt->valueTab[ctxt->valueNr] = NULL;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002499 return (ret);
2500}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002501/**
2502 * valuePush:
2503 * @ctxt: an XPath evaluation context
2504 * @value: the XPath object
2505 *
2506 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002507 *
2508 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002509 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002510int
Daniel Veillard1c732d22002-11-30 11:22:59 +00002511valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2512{
Daniel Veillarda82b1822004-11-08 16:24:57 +00002513 if ((ctxt == NULL) || (value == NULL)) return(-1);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002514 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002515 xmlXPathObjectPtr *tmp;
2516
Daniel Veillardcd852ad2012-07-30 10:12:18 +08002517 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2518 xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
2519 ctxt->error = XPATH_MEMORY_ERROR;
2520 return (0);
2521 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002522 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2523 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00002524 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002525 if (tmp == NULL) {
Daniel Veillardcd852ad2012-07-30 10:12:18 +08002526 xmlXPathErrMemory(NULL, "pushing value\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08002527 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002528 return (0);
2529 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002530 ctxt->valueMax *= 2;
2531 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002532 }
2533 ctxt->valueTab[ctxt->valueNr] = value;
2534 ctxt->value = value;
2535 return (ctxt->valueNr++);
2536}
Owen Taylor3473f882001-02-23 17:55:21 +00002537
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002538/**
2539 * xmlXPathPopBoolean:
2540 * @ctxt: an XPath parser context
2541 *
2542 * Pops a boolean from the stack, handling conversion if needed.
2543 * Check error with #xmlXPathCheckError.
2544 *
2545 * Returns the boolean
2546 */
2547int
2548xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2549 xmlXPathObjectPtr obj;
2550 int ret;
2551
2552 obj = valuePop(ctxt);
2553 if (obj == NULL) {
2554 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2555 return(0);
2556 }
William M. Brack08171912003-12-29 02:52:11 +00002557 if (obj->type != XPATH_BOOLEAN)
2558 ret = xmlXPathCastToBoolean(obj);
2559 else
2560 ret = obj->boolval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002561 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002562 return(ret);
2563}
2564
2565/**
2566 * xmlXPathPopNumber:
2567 * @ctxt: an XPath parser context
2568 *
2569 * Pops a number from the stack, handling conversion if needed.
2570 * Check error with #xmlXPathCheckError.
2571 *
2572 * Returns the number
2573 */
2574double
2575xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2576 xmlXPathObjectPtr obj;
2577 double ret;
2578
2579 obj = valuePop(ctxt);
2580 if (obj == NULL) {
2581 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2582 return(0);
2583 }
William M. Brack08171912003-12-29 02:52:11 +00002584 if (obj->type != XPATH_NUMBER)
2585 ret = xmlXPathCastToNumber(obj);
2586 else
2587 ret = obj->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002588 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002589 return(ret);
2590}
2591
2592/**
2593 * xmlXPathPopString:
2594 * @ctxt: an XPath parser context
2595 *
2596 * Pops a string from the stack, handling conversion if needed.
2597 * Check error with #xmlXPathCheckError.
2598 *
2599 * Returns the string
2600 */
2601xmlChar *
2602xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2603 xmlXPathObjectPtr obj;
2604 xmlChar * ret;
2605
2606 obj = valuePop(ctxt);
2607 if (obj == NULL) {
2608 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2609 return(NULL);
2610 }
William M. Brack08171912003-12-29 02:52:11 +00002611 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002612 /* TODO: needs refactoring somewhere else */
2613 if (obj->stringval == ret)
2614 obj->stringval = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002615 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002616 return(ret);
2617}
2618
2619/**
2620 * xmlXPathPopNodeSet:
2621 * @ctxt: an XPath parser context
2622 *
2623 * Pops a node-set from the stack, handling conversion if needed.
2624 * Check error with #xmlXPathCheckError.
2625 *
2626 * Returns the node-set
2627 */
2628xmlNodeSetPtr
2629xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2630 xmlXPathObjectPtr obj;
2631 xmlNodeSetPtr ret;
2632
Daniel Veillardf2a36f92004-11-08 17:55:01 +00002633 if (ctxt == NULL) return(NULL);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002634 if (ctxt->value == NULL) {
2635 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2636 return(NULL);
2637 }
2638 if (!xmlXPathStackIsNodeSet(ctxt)) {
2639 xmlXPathSetTypeError(ctxt);
2640 return(NULL);
2641 }
2642 obj = valuePop(ctxt);
2643 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00002644#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00002645 /* to fix memory leak of not clearing obj->user */
2646 if (obj->boolval && obj->user != NULL)
2647 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00002648#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002649 obj->nodesetval = NULL;
2650 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002651 return(ret);
2652}
2653
2654/**
2655 * xmlXPathPopExternal:
2656 * @ctxt: an XPath parser context
2657 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002658 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002659 * Check error with #xmlXPathCheckError.
2660 *
2661 * Returns the object
2662 */
2663void *
2664xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2665 xmlXPathObjectPtr obj;
2666 void * ret;
2667
Daniel Veillarda82b1822004-11-08 16:24:57 +00002668 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002669 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2670 return(NULL);
2671 }
2672 if (ctxt->value->type != XPATH_USERS) {
2673 xmlXPathSetTypeError(ctxt);
2674 return(NULL);
2675 }
2676 obj = valuePop(ctxt);
2677 ret = obj->user;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002678 obj->user = NULL;
2679 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002680 return(ret);
2681}
2682
Owen Taylor3473f882001-02-23 17:55:21 +00002683/*
2684 * Macros for accessing the content. Those should be used only by the parser,
2685 * and not exported.
2686 *
2687 * Dirty macros, i.e. one need to make assumption on the context to use them
2688 *
2689 * CUR_PTR return the current pointer to the xmlChar to be parsed.
2690 * CUR returns the current xmlChar value, i.e. a 8 bit value
2691 * in ISO-Latin or UTF-8.
2692 * This should be used internally by the parser
2693 * only to compare to ASCII values otherwise it would break when
2694 * running with UTF-8 encoding.
2695 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
2696 * to compare on ASCII based substring.
2697 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2698 * strings within the parser.
2699 * CURRENT Returns the current char value, with the full decoding of
2700 * UTF-8 if we are using this mode. It returns an int.
2701 * NEXT Skip to the next character, this does the proper decoding
2702 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
2703 * It returns the pointer to the current xmlChar.
2704 */
2705
2706#define CUR (*ctxt->cur)
2707#define SKIP(val) ctxt->cur += (val)
2708#define NXT(val) ctxt->cur[(val)]
2709#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00002710#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2711
2712#define COPY_BUF(l,b,i,v) \
2713 if (l == 1) b[i++] = (xmlChar) v; \
2714 else i += xmlCopyChar(l,&b[i],v)
2715
2716#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00002717
Daniel Veillard45490ae2008-07-29 09:13:19 +00002718#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00002719 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00002720
2721#define CURRENT (*ctxt->cur)
2722#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
2723
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002724
2725#ifndef DBL_DIG
2726#define DBL_DIG 16
2727#endif
2728#ifndef DBL_EPSILON
2729#define DBL_EPSILON 1E-9
2730#endif
2731
2732#define UPPER_DOUBLE 1E9
2733#define LOWER_DOUBLE 1E-5
William M. Brackca797882007-05-11 14:45:53 +00002734#define LOWER_DOUBLE_EXP 5
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002735
2736#define INTEGER_DIGITS DBL_DIG
William M. Brackca797882007-05-11 14:45:53 +00002737#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002738#define EXPONENT_DIGITS (3 + 2)
2739
2740/**
2741 * xmlXPathFormatNumber:
2742 * @number: number to format
2743 * @buffer: output buffer
2744 * @buffersize: size of output buffer
2745 *
2746 * Convert the number into a string representation.
2747 */
2748static void
2749xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2750{
Daniel Veillardcda96922001-08-21 10:56:31 +00002751 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002752 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00002753 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002754 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002755 break;
2756 case -1:
2757 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 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00002761 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002762 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002763 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00002764 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002765 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002766 } else if (number == ((int) number)) {
2767 char work[30];
2768 char *ptr, *cur;
Daniel Veillardb3d14912005-09-04 20:47:39 +00002769 int value = (int) number;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002770
2771 ptr = &buffer[0];
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002772 if (value == 0) {
2773 *ptr++ = '0';
2774 } else {
Daniel Veillardb3d14912005-09-04 20:47:39 +00002775 snprintf(work, 29, "%d", value);
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002776 cur = &work[0];
Daniel Veillardb3d14912005-09-04 20:47:39 +00002777 while ((*cur) && (ptr - buffer < buffersize)) {
2778 *ptr++ = *cur++;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002779 }
2780 }
2781 if (ptr - buffer < buffersize) {
2782 *ptr = 0;
2783 } else if (buffersize > 0) {
2784 ptr--;
2785 *ptr = 0;
2786 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002787 } else {
William M. Brackca797882007-05-11 14:45:53 +00002788 /*
2789 For the dimension of work,
2790 DBL_DIG is number of significant digits
2791 EXPONENT is only needed for "scientific notation"
2792 3 is sign, decimal point, and terminating zero
2793 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2794 Note that this dimension is slightly (a few characters)
2795 larger than actually necessary.
2796 */
2797 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
Bjorn Reese70a9da52001-04-21 16:57:29 +00002798 int integer_place, fraction_place;
2799 char *ptr;
2800 char *after_fraction;
2801 double absolute_value;
2802 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002803
Bjorn Reese70a9da52001-04-21 16:57:29 +00002804 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002805
Bjorn Reese70a9da52001-04-21 16:57:29 +00002806 /*
2807 * First choose format - scientific or regular floating point.
2808 * In either case, result is in work, and after_fraction points
2809 * just past the fractional part.
2810 */
2811 if ( ((absolute_value > UPPER_DOUBLE) ||
2812 (absolute_value < LOWER_DOUBLE)) &&
2813 (absolute_value != 0.0) ) {
2814 /* Use scientific notation */
2815 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2816 fraction_place = DBL_DIG - 1;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002817 size = snprintf(work, sizeof(work),"%*.*e",
Bjorn Reese70a9da52001-04-21 16:57:29 +00002818 integer_place, fraction_place, number);
Daniel Veillard11ce4002006-03-10 00:36:23 +00002819 while ((size > 0) && (work[size] != 'e')) size--;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002820
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002821 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002822 else {
2823 /* Use regular notation */
William M. Brackca797882007-05-11 14:45:53 +00002824 if (absolute_value > 0.0) {
2825 integer_place = (int)log10(absolute_value);
2826 if (integer_place > 0)
2827 fraction_place = DBL_DIG - integer_place - 1;
2828 else
2829 fraction_place = DBL_DIG - integer_place;
2830 } else {
2831 fraction_place = 1;
2832 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002833 size = snprintf(work, sizeof(work), "%0.*f",
2834 fraction_place, number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002835 }
2836
Bjorn Reese70a9da52001-04-21 16:57:29 +00002837 /* Remove fractional trailing zeroes */
William M. Brackca797882007-05-11 14:45:53 +00002838 after_fraction = work + size;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002839 ptr = after_fraction;
2840 while (*(--ptr) == '0')
2841 ;
2842 if (*ptr != '.')
2843 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002844 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002845
2846 /* Finally copy result back to caller */
2847 size = strlen(work) + 1;
2848 if (size > buffersize) {
2849 work[buffersize - 1] = 0;
2850 size = buffersize;
2851 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002852 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002853 }
2854 break;
2855 }
2856}
2857
Owen Taylor3473f882001-02-23 17:55:21 +00002858
2859/************************************************************************
2860 * *
2861 * Routines to handle NodeSets *
2862 * *
2863 ************************************************************************/
2864
2865/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002866 * xmlXPathOrderDocElems:
2867 * @doc: an input document
2868 *
2869 * Call this routine to speed up XPath computation on static documents.
2870 * This stamps all the element nodes with the document order
2871 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00002872 * field, the value stored is actually - the node number (starting at -1)
2873 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002874 *
William M. Brack08171912003-12-29 02:52:11 +00002875 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002876 * of error.
2877 */
2878long
2879xmlXPathOrderDocElems(xmlDocPtr doc) {
2880 long count = 0;
2881 xmlNodePtr cur;
2882
2883 if (doc == NULL)
2884 return(-1);
2885 cur = doc->children;
2886 while (cur != NULL) {
2887 if (cur->type == XML_ELEMENT_NODE) {
2888 cur->content = (void *) (-(++count));
2889 if (cur->children != NULL) {
2890 cur = cur->children;
2891 continue;
2892 }
2893 }
2894 if (cur->next != NULL) {
2895 cur = cur->next;
2896 continue;
2897 }
2898 do {
2899 cur = cur->parent;
2900 if (cur == NULL)
2901 break;
2902 if (cur == (xmlNodePtr) doc) {
2903 cur = NULL;
2904 break;
2905 }
2906 if (cur->next != NULL) {
2907 cur = cur->next;
2908 break;
2909 }
2910 } while (cur != NULL);
2911 }
2912 return(count);
2913}
2914
2915/**
Owen Taylor3473f882001-02-23 17:55:21 +00002916 * xmlXPathCmpNodes:
2917 * @node1: the first node
2918 * @node2: the second node
2919 *
2920 * Compare two nodes w.r.t document order
2921 *
2922 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00002923 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00002924 */
2925int
2926xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2927 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002928 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002929 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002930 xmlNodePtr cur, root;
2931
2932 if ((node1 == NULL) || (node2 == NULL))
2933 return(-2);
2934 /*
2935 * a couple of optimizations which will avoid computations in most cases
2936 */
William M. Brackee0b9822007-03-07 08:15:01 +00002937 if (node1 == node2) /* trivial case */
2938 return(0);
Daniel Veillardedfd5882003-03-07 14:20:40 +00002939 if (node1->type == XML_ATTRIBUTE_NODE) {
2940 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002941 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002942 node1 = node1->parent;
2943 }
2944 if (node2->type == XML_ATTRIBUTE_NODE) {
2945 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002946 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002947 node2 = node2->parent;
2948 }
2949 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00002950 if (attr1 == attr2) {
2951 /* not required, but we keep attributes in order */
2952 if (attr1 != 0) {
2953 cur = attrNode2->prev;
2954 while (cur != NULL) {
2955 if (cur == attrNode1)
2956 return (1);
2957 cur = cur->prev;
2958 }
2959 return (-1);
2960 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00002961 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00002962 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00002963 if (attr2 == 1)
2964 return(1);
2965 return(-1);
2966 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002967 if ((node1->type == XML_NAMESPACE_DECL) ||
2968 (node2->type == XML_NAMESPACE_DECL))
2969 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00002970 if (node1 == node2->prev)
2971 return(1);
2972 if (node1 == node2->next)
2973 return(-1);
2974
2975 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002976 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002977 */
2978 if ((node1->type == XML_ELEMENT_NODE) &&
2979 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002980 (0 > (long) node1->content) &&
2981 (0 > (long) node2->content) &&
2982 (node1->doc == node2->doc)) {
2983 long l1, l2;
2984
2985 l1 = -((long) node1->content);
2986 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002987 if (l1 < l2)
2988 return(1);
2989 if (l1 > l2)
2990 return(-1);
2991 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002992
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002993 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002994 * compute depth to root
2995 */
2996 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2997 if (cur == node1)
2998 return(1);
2999 depth2++;
3000 }
3001 root = cur;
3002 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3003 if (cur == node2)
3004 return(-1);
3005 depth1++;
3006 }
3007 /*
3008 * Distinct document (or distinct entities :-( ) case.
3009 */
3010 if (root != cur) {
3011 return(-2);
3012 }
3013 /*
3014 * get the nearest common ancestor.
3015 */
3016 while (depth1 > depth2) {
3017 depth1--;
3018 node1 = node1->parent;
3019 }
3020 while (depth2 > depth1) {
3021 depth2--;
3022 node2 = node2->parent;
3023 }
3024 while (node1->parent != node2->parent) {
3025 node1 = node1->parent;
3026 node2 = node2->parent;
3027 /* should not happen but just in case ... */
3028 if ((node1 == NULL) || (node2 == NULL))
3029 return(-2);
3030 }
3031 /*
3032 * Find who's first.
3033 */
Daniel Veillardf49be472004-02-17 11:48:18 +00003034 if (node1 == node2->prev)
3035 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00003036 if (node1 == node2->next)
3037 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00003038 /*
3039 * Speedup using document order if availble.
3040 */
3041 if ((node1->type == XML_ELEMENT_NODE) &&
3042 (node2->type == XML_ELEMENT_NODE) &&
3043 (0 > (long) node1->content) &&
3044 (0 > (long) node2->content) &&
3045 (node1->doc == node2->doc)) {
3046 long l1, l2;
3047
3048 l1 = -((long) node1->content);
3049 l2 = -((long) node2->content);
3050 if (l1 < l2)
3051 return(1);
3052 if (l1 > l2)
3053 return(-1);
3054 }
3055
Owen Taylor3473f882001-02-23 17:55:21 +00003056 for (cur = node1->next;cur != NULL;cur = cur->next)
3057 if (cur == node2)
3058 return(1);
3059 return(-1); /* assume there is no sibling list corruption */
3060}
3061
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003062#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003063/**
3064 * xmlXPathCmpNodesExt:
3065 * @node1: the first node
3066 * @node2: the second node
3067 *
3068 * Compare two nodes w.r.t document order.
3069 * This one is optimized for handling of non-element nodes.
3070 *
3071 * Returns -2 in case of error 1 if first point < second point, 0 if
3072 * it's the same node, -1 otherwise
3073 */
3074static int
3075xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
3076 int depth1, depth2;
3077 int misc = 0, precedence1 = 0, precedence2 = 0;
3078 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
3079 xmlNodePtr cur, root;
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003080 long l1, l2;
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003081
3082 if ((node1 == NULL) || (node2 == NULL))
3083 return(-2);
3084
3085 if (node1 == node2)
3086 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00003087
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003088 /*
3089 * a couple of optimizations which will avoid computations in most cases
Daniel Veillard45490ae2008-07-29 09:13:19 +00003090 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003091 switch (node1->type) {
3092 case XML_ELEMENT_NODE:
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003093 if (node2->type == XML_ELEMENT_NODE) {
3094 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
3095 (0 > (long) node2->content) &&
3096 (node1->doc == node2->doc))
Daniel Veillard45490ae2008-07-29 09:13:19 +00003097 {
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003098 l1 = -((long) node1->content);
3099 l2 = -((long) node2->content);
3100 if (l1 < l2)
3101 return(1);
3102 if (l1 > l2)
3103 return(-1);
3104 } else
Daniel Veillard45490ae2008-07-29 09:13:19 +00003105 goto turtle_comparison;
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003106 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003107 break;
3108 case XML_ATTRIBUTE_NODE:
3109 precedence1 = 1; /* element is owner */
3110 miscNode1 = node1;
3111 node1 = node1->parent;
3112 misc = 1;
3113 break;
3114 case XML_TEXT_NODE:
3115 case XML_CDATA_SECTION_NODE:
3116 case XML_COMMENT_NODE:
3117 case XML_PI_NODE: {
3118 miscNode1 = node1;
3119 /*
3120 * Find nearest element node.
Daniel Veillard45490ae2008-07-29 09:13:19 +00003121 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003122 if (node1->prev != NULL) {
3123 do {
3124 node1 = node1->prev;
3125 if (node1->type == XML_ELEMENT_NODE) {
3126 precedence1 = 3; /* element in prev-sibl axis */
3127 break;
3128 }
3129 if (node1->prev == NULL) {
3130 precedence1 = 2; /* element is parent */
3131 /*
3132 * URGENT TODO: Are there any cases, where the
3133 * parent of such a node is not an element node?
3134 */
3135 node1 = node1->parent;
3136 break;
3137 }
3138 } while (1);
3139 } else {
3140 precedence1 = 2; /* element is parent */
3141 node1 = node1->parent;
3142 }
William M. Brack31700e62007-06-13 20:33:02 +00003143 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
3144 (0 <= (long) node1->content)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003145 /*
3146 * Fallback for whatever case.
3147 */
3148 node1 = miscNode1;
3149 precedence1 = 0;
3150 } else
3151 misc = 1;
3152 }
3153 break;
3154 case XML_NAMESPACE_DECL:
3155 /*
3156 * TODO: why do we return 1 for namespace nodes?
3157 */
3158 return(1);
3159 default:
3160 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00003161 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003162 switch (node2->type) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00003163 case XML_ELEMENT_NODE:
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003164 break;
3165 case XML_ATTRIBUTE_NODE:
3166 precedence2 = 1; /* element is owner */
3167 miscNode2 = node2;
3168 node2 = node2->parent;
3169 misc = 1;
3170 break;
3171 case XML_TEXT_NODE:
3172 case XML_CDATA_SECTION_NODE:
3173 case XML_COMMENT_NODE:
3174 case XML_PI_NODE: {
3175 miscNode2 = node2;
3176 if (node2->prev != NULL) {
3177 do {
3178 node2 = node2->prev;
3179 if (node2->type == XML_ELEMENT_NODE) {
3180 precedence2 = 3; /* element in prev-sibl axis */
3181 break;
3182 }
3183 if (node2->prev == NULL) {
3184 precedence2 = 2; /* element is parent */
3185 node2 = node2->parent;
3186 break;
3187 }
3188 } while (1);
3189 } else {
3190 precedence2 = 2; /* element is parent */
3191 node2 = node2->parent;
Daniel Veillard45490ae2008-07-29 09:13:19 +00003192 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003193 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3194 (0 <= (long) node1->content))
3195 {
3196 node2 = miscNode2;
3197 precedence2 = 0;
3198 } else
3199 misc = 1;
3200 }
3201 break;
3202 case XML_NAMESPACE_DECL:
3203 return(1);
3204 default:
3205 break;
3206 }
3207 if (misc) {
3208 if (node1 == node2) {
3209 if (precedence1 == precedence2) {
3210 /*
3211 * The ugly case; but normally there aren't many
3212 * adjacent non-element nodes around.
3213 */
3214 cur = miscNode2->prev;
3215 while (cur != NULL) {
3216 if (cur == miscNode1)
3217 return(1);
3218 if (cur->type == XML_ELEMENT_NODE)
3219 return(-1);
3220 cur = cur->prev;
3221 }
3222 return (-1);
3223 } else {
3224 /*
3225 * Evaluate based on higher precedence wrt to the element.
3226 * TODO: This assumes attributes are sorted before content.
3227 * Is this 100% correct?
3228 */
3229 if (precedence1 < precedence2)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003230 return(1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003231 else
Daniel Veillard45490ae2008-07-29 09:13:19 +00003232 return(-1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003233 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00003234 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003235 /*
3236 * Special case: One of the helper-elements is contained by the other.
3237 * <foo>
3238 * <node2>
3239 * <node1>Text-1(precedence1 == 2)</node1>
3240 * </node2>
3241 * Text-6(precedence2 == 3)
3242 * </foo>
Daniel Veillard45490ae2008-07-29 09:13:19 +00003243 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003244 if ((precedence2 == 3) && (precedence1 > 1)) {
3245 cur = node1->parent;
3246 while (cur) {
3247 if (cur == node2)
3248 return(1);
3249 cur = cur->parent;
3250 }
3251 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00003252 if ((precedence1 == 3) && (precedence2 > 1)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003253 cur = node2->parent;
3254 while (cur) {
3255 if (cur == node1)
3256 return(-1);
3257 cur = cur->parent;
3258 }
3259 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00003260 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003261
3262 /*
3263 * Speedup using document order if availble.
3264 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00003265 if ((node1->type == XML_ELEMENT_NODE) &&
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003266 (node2->type == XML_ELEMENT_NODE) &&
3267 (0 > (long) node1->content) &&
3268 (0 > (long) node2->content) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +00003269 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003270
3271 l1 = -((long) node1->content);
3272 l2 = -((long) node2->content);
3273 if (l1 < l2)
3274 return(1);
3275 if (l1 > l2)
3276 return(-1);
3277 }
3278
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003279turtle_comparison:
3280
3281 if (node1 == node2->prev)
3282 return(1);
3283 if (node1 == node2->next)
3284 return(-1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003285 /*
3286 * compute depth to root
3287 */
3288 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3289 if (cur == node1)
3290 return(1);
3291 depth2++;
3292 }
3293 root = cur;
3294 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3295 if (cur == node2)
3296 return(-1);
3297 depth1++;
3298 }
3299 /*
3300 * Distinct document (or distinct entities :-( ) case.
3301 */
3302 if (root != cur) {
3303 return(-2);
3304 }
3305 /*
3306 * get the nearest common ancestor.
3307 */
3308 while (depth1 > depth2) {
3309 depth1--;
3310 node1 = node1->parent;
3311 }
3312 while (depth2 > depth1) {
3313 depth2--;
3314 node2 = node2->parent;
3315 }
3316 while (node1->parent != node2->parent) {
3317 node1 = node1->parent;
3318 node2 = node2->parent;
3319 /* should not happen but just in case ... */
3320 if ((node1 == NULL) || (node2 == NULL))
3321 return(-2);
3322 }
3323 /*
3324 * Find who's first.
3325 */
3326 if (node1 == node2->prev)
3327 return(1);
3328 if (node1 == node2->next)
3329 return(-1);
3330 /*
3331 * Speedup using document order if availble.
3332 */
3333 if ((node1->type == XML_ELEMENT_NODE) &&
3334 (node2->type == XML_ELEMENT_NODE) &&
3335 (0 > (long) node1->content) &&
3336 (0 > (long) node2->content) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +00003337 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003338
3339 l1 = -((long) node1->content);
3340 l2 = -((long) node2->content);
3341 if (l1 < l2)
3342 return(1);
3343 if (l1 > l2)
3344 return(-1);
3345 }
3346
3347 for (cur = node1->next;cur != NULL;cur = cur->next)
3348 if (cur == node2)
3349 return(1);
3350 return(-1); /* assume there is no sibling list corruption */
3351}
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003352#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003353
Owen Taylor3473f882001-02-23 17:55:21 +00003354/**
3355 * xmlXPathNodeSetSort:
3356 * @set: the node set
3357 *
3358 * Sort the node set in document order
3359 */
3360void
3361xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003362 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003363 xmlNodePtr tmp;
3364
3365 if (set == NULL)
3366 return;
3367
3368 /* Use Shell's sort to sort the node-set */
3369 len = set->nodeNr;
3370 for (incr = len / 2; incr > 0; incr /= 2) {
3371 for (i = incr; i < len; i++) {
3372 j = i - incr;
3373 while (j >= 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003374#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003375 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3376 set->nodeTab[j + incr]) == -1)
3377#else
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003378 if (xmlXPathCmpNodes(set->nodeTab[j],
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003379 set->nodeTab[j + incr]) == -1)
3380#endif
3381 {
Owen Taylor3473f882001-02-23 17:55:21 +00003382 tmp = set->nodeTab[j];
3383 set->nodeTab[j] = set->nodeTab[j + incr];
3384 set->nodeTab[j + incr] = tmp;
3385 j -= incr;
3386 } else
3387 break;
3388 }
3389 }
3390 }
3391}
3392
3393#define XML_NODESET_DEFAULT 10
3394/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003395 * xmlXPathNodeSetDupNs:
3396 * @node: the parent node of the namespace XPath node
3397 * @ns: the libxml namespace declaration node.
3398 *
3399 * Namespace node in libxml don't match the XPath semantic. In a node set
3400 * the namespace nodes are duplicated and the next pointer is set to the
3401 * parent node in the XPath semantic.
3402 *
3403 * Returns the newly created object.
3404 */
3405static xmlNodePtr
3406xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3407 xmlNsPtr cur;
3408
3409 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3410 return(NULL);
3411 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3412 return((xmlNodePtr) ns);
3413
3414 /*
3415 * Allocate a new Namespace and fill the fields.
3416 */
3417 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3418 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003419 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003420 return(NULL);
3421 }
3422 memset(cur, 0, sizeof(xmlNs));
3423 cur->type = XML_NAMESPACE_DECL;
3424 if (ns->href != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003425 cur->href = xmlStrdup(ns->href);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003426 if (ns->prefix != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003427 cur->prefix = xmlStrdup(ns->prefix);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003428 cur->next = (xmlNsPtr) node;
3429 return((xmlNodePtr) cur);
3430}
3431
3432/**
3433 * xmlXPathNodeSetFreeNs:
3434 * @ns: the XPath namespace node found in a nodeset.
3435 *
William M. Brack08171912003-12-29 02:52:11 +00003436 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003437 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00003438 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003439 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00003440void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003441xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3442 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3443 return;
3444
3445 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3446 if (ns->href != NULL)
3447 xmlFree((xmlChar *)ns->href);
3448 if (ns->prefix != NULL)
3449 xmlFree((xmlChar *)ns->prefix);
3450 xmlFree(ns);
3451 }
3452}
3453
3454/**
Owen Taylor3473f882001-02-23 17:55:21 +00003455 * xmlXPathNodeSetCreate:
3456 * @val: an initial xmlNodePtr, or NULL
3457 *
3458 * Create a new xmlNodeSetPtr of type double and of value @val
3459 *
3460 * Returns the newly created object.
3461 */
3462xmlNodeSetPtr
3463xmlXPathNodeSetCreate(xmlNodePtr val) {
3464 xmlNodeSetPtr ret;
3465
3466 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3467 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003468 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003469 return(NULL);
3470 }
3471 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3472 if (val != NULL) {
3473 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3474 sizeof(xmlNodePtr));
3475 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003476 xmlXPathErrMemory(NULL, "creating nodeset\n");
3477 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003478 return(NULL);
3479 }
3480 memset(ret->nodeTab, 0 ,
3481 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3482 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003483 if (val->type == XML_NAMESPACE_DECL) {
3484 xmlNsPtr ns = (xmlNsPtr) val;
3485
3486 ret->nodeTab[ret->nodeNr++] =
3487 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3488 } else
3489 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003490 }
3491 return(ret);
3492}
3493
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003494/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003495 * xmlXPathNodeSetCreateSize:
3496 * @size: the initial size of the set
3497 *
3498 * Create a new xmlNodeSetPtr of type double and of value @val
3499 *
3500 * Returns the newly created object.
3501 */
3502static xmlNodeSetPtr
3503xmlXPathNodeSetCreateSize(int size) {
3504 xmlNodeSetPtr ret;
3505
3506 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3507 if (ret == NULL) {
3508 xmlXPathErrMemory(NULL, "creating nodeset\n");
3509 return(NULL);
3510 }
3511 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3512 if (size < XML_NODESET_DEFAULT)
3513 size = XML_NODESET_DEFAULT;
3514 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3515 if (ret->nodeTab == NULL) {
3516 xmlXPathErrMemory(NULL, "creating nodeset\n");
3517 xmlFree(ret);
3518 return(NULL);
3519 }
3520 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
Daniel Veillard45490ae2008-07-29 09:13:19 +00003521 ret->nodeMax = size;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003522 return(ret);
3523}
3524
3525/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003526 * xmlXPathNodeSetContains:
3527 * @cur: the node-set
3528 * @val: the node
3529 *
3530 * checks whether @cur contains @val
3531 *
3532 * Returns true (1) if @cur contains @val, false (0) otherwise
3533 */
3534int
3535xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3536 int i;
3537
Daniel Veillarda82b1822004-11-08 16:24:57 +00003538 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003539 if (val->type == XML_NAMESPACE_DECL) {
3540 for (i = 0; i < cur->nodeNr; i++) {
3541 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3542 xmlNsPtr ns1, ns2;
3543
3544 ns1 = (xmlNsPtr) val;
3545 ns2 = (xmlNsPtr) cur->nodeTab[i];
3546 if (ns1 == ns2)
3547 return(1);
3548 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3549 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3550 return(1);
3551 }
3552 }
3553 } else {
3554 for (i = 0; i < cur->nodeNr; i++) {
3555 if (cur->nodeTab[i] == val)
3556 return(1);
3557 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003558 }
3559 return(0);
3560}
3561
3562/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003563 * xmlXPathNodeSetAddNs:
3564 * @cur: the initial node set
3565 * @node: the hosting node
3566 * @ns: a the namespace node
3567 *
3568 * add a new namespace node to an existing NodeSet
3569 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00003570void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003571xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3572 int i;
3573
Daniel Veillard45490ae2008-07-29 09:13:19 +00003574
Daniel Veillarda82b1822004-11-08 16:24:57 +00003575 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3576 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003577 (node->type != XML_ELEMENT_NODE))
3578 return;
3579
William M. Brack08171912003-12-29 02:52:11 +00003580 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003581 /*
William M. Brack08171912003-12-29 02:52:11 +00003582 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003583 */
3584 for (i = 0;i < cur->nodeNr;i++) {
3585 if ((cur->nodeTab[i] != NULL) &&
3586 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00003587 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003588 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3589 return;
3590 }
3591
3592 /*
3593 * grow the nodeTab if needed
3594 */
3595 if (cur->nodeMax == 0) {
3596 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3597 sizeof(xmlNodePtr));
3598 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003599 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003600 return;
3601 }
3602 memset(cur->nodeTab, 0 ,
3603 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3604 cur->nodeMax = XML_NODESET_DEFAULT;
3605 } else if (cur->nodeNr == cur->nodeMax) {
3606 xmlNodePtr *temp;
3607
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003608 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3609 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3610 return;
3611 }
Chris Evansd7958b22011-03-23 08:13:06 +08003612 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003613 sizeof(xmlNodePtr));
3614 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003615 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003616 return;
3617 }
Chris Evansd7958b22011-03-23 08:13:06 +08003618 cur->nodeMax *= 2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003619 cur->nodeTab = temp;
3620 }
3621 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3622}
3623
3624/**
Owen Taylor3473f882001-02-23 17:55:21 +00003625 * xmlXPathNodeSetAdd:
3626 * @cur: the initial node set
3627 * @val: a new xmlNodePtr
3628 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003629 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00003630 */
3631void
3632xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3633 int i;
3634
Daniel Veillarda82b1822004-11-08 16:24:57 +00003635 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003636
William M. Brack08171912003-12-29 02:52:11 +00003637 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003638 /*
William M. Brack08171912003-12-29 02:52:11 +00003639 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00003640 */
3641 for (i = 0;i < cur->nodeNr;i++)
3642 if (cur->nodeTab[i] == val) return;
3643
3644 /*
3645 * grow the nodeTab if needed
3646 */
3647 if (cur->nodeMax == 0) {
3648 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3649 sizeof(xmlNodePtr));
3650 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003651 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003652 return;
3653 }
3654 memset(cur->nodeTab, 0 ,
3655 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3656 cur->nodeMax = XML_NODESET_DEFAULT;
3657 } else if (cur->nodeNr == cur->nodeMax) {
3658 xmlNodePtr *temp;
3659
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003660 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3661 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3662 return;
3663 }
Daniel Veillard0cbeb502010-11-15 12:06:29 +01003664 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003665 sizeof(xmlNodePtr));
3666 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003667 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003668 return;
3669 }
Daniel Veillard0cbeb502010-11-15 12:06:29 +01003670 cur->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003671 cur->nodeTab = temp;
3672 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003673 if (val->type == XML_NAMESPACE_DECL) {
3674 xmlNsPtr ns = (xmlNsPtr) val;
3675
Daniel Veillard45490ae2008-07-29 09:13:19 +00003676 cur->nodeTab[cur->nodeNr++] =
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003677 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3678 } else
3679 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003680}
3681
3682/**
3683 * xmlXPathNodeSetAddUnique:
3684 * @cur: the initial node set
3685 * @val: a new xmlNodePtr
3686 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003687 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00003688 * when we are sure the node is not already in the set.
3689 */
3690void
3691xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00003692 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003693
William M. Brack08171912003-12-29 02:52:11 +00003694 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003695 /*
3696 * grow the nodeTab if needed
3697 */
3698 if (cur->nodeMax == 0) {
3699 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3700 sizeof(xmlNodePtr));
3701 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003702 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003703 return;
3704 }
3705 memset(cur->nodeTab, 0 ,
3706 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3707 cur->nodeMax = XML_NODESET_DEFAULT;
3708 } else if (cur->nodeNr == cur->nodeMax) {
3709 xmlNodePtr *temp;
3710
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003711 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3712 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3713 return;
3714 }
Chris Evansd7958b22011-03-23 08:13:06 +08003715 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003716 sizeof(xmlNodePtr));
3717 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003718 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003719 return;
3720 }
3721 cur->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08003722 cur->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003723 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003724 if (val->type == XML_NAMESPACE_DECL) {
3725 xmlNsPtr ns = (xmlNsPtr) val;
3726
Daniel Veillard45490ae2008-07-29 09:13:19 +00003727 cur->nodeTab[cur->nodeNr++] =
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003728 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3729 } else
3730 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003731}
3732
3733/**
3734 * xmlXPathNodeSetMerge:
3735 * @val1: the first NodeSet or NULL
3736 * @val2: the second NodeSet
3737 *
3738 * Merges two nodesets, all nodes from @val2 are added to @val1
3739 * if @val1 is NULL, a new set is created and copied from @val2
3740 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003741 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003742 */
3743xmlNodeSetPtr
3744xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003745 int i, j, initNr, skip;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003746 xmlNodePtr n1, n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003747
3748 if (val2 == NULL) return(val1);
3749 if (val1 == NULL) {
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003750 val1 = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00003751 if (val1 == NULL)
3752 return (NULL);
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003753#if 0
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003754 /*
3755 * TODO: The optimization won't work in every case, since
3756 * those nasty namespace nodes need to be added with
3757 * xmlXPathNodeSetDupNs() to the set; thus a pure
3758 * memcpy is not possible.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00003759 * If there was a flag on the nodesetval, indicating that
3760 * some temporary nodes are in, that would be helpfull.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003761 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00003762 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003763 * Optimization: Create an equally sized node-set
3764 * and memcpy the content.
3765 */
3766 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3767 if (val1 == NULL)
3768 return(NULL);
3769 if (val2->nodeNr != 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003770 if (val2->nodeNr == 1)
3771 *(val1->nodeTab) = *(val2->nodeTab);
3772 else {
3773 memcpy(val1->nodeTab, val2->nodeTab,
3774 val2->nodeNr * sizeof(xmlNodePtr));
3775 }
3776 val1->nodeNr = val2->nodeNr;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003777 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003778 return(val1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003779#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003780 }
3781
William M. Brack08171912003-12-29 02:52:11 +00003782 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003783 initNr = val1->nodeNr;
3784
3785 for (i = 0;i < val2->nodeNr;i++) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00003786 n2 = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00003787 /*
William M. Brack08171912003-12-29 02:52:11 +00003788 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003789 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003790 skip = 0;
3791 for (j = 0; j < initNr; j++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003792 n1 = val1->nodeTab[j];
3793 if (n1 == n2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003794 skip = 1;
3795 break;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003796 } else if ((n1->type == XML_NAMESPACE_DECL) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +00003797 (n2->type == XML_NAMESPACE_DECL)) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003798 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3799 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3800 ((xmlNsPtr) n2)->prefix)))
3801 {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003802 skip = 1;
3803 break;
3804 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003805 }
3806 }
3807 if (skip)
3808 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00003809
3810 /*
3811 * grow the nodeTab if needed
3812 */
3813 if (val1->nodeMax == 0) {
3814 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3815 sizeof(xmlNodePtr));
3816 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003817 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003818 return(NULL);
3819 }
3820 memset(val1->nodeTab, 0 ,
3821 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3822 val1->nodeMax = XML_NODESET_DEFAULT;
3823 } else if (val1->nodeNr == val1->nodeMax) {
3824 xmlNodePtr *temp;
3825
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003826 if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3827 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3828 return(NULL);
3829 }
Chris Evansd7958b22011-03-23 08:13:06 +08003830 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003831 sizeof(xmlNodePtr));
3832 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003833 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003834 return(NULL);
3835 }
3836 val1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08003837 val1->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003838 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003839 if (n2->type == XML_NAMESPACE_DECL) {
3840 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003841
3842 val1->nodeTab[val1->nodeNr++] =
3843 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3844 } else
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003845 val1->nodeTab[val1->nodeNr++] = n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003846 }
3847
3848 return(val1);
3849}
3850
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003851
3852/**
3853 * xmlXPathNodeSetMergeAndClear:
3854 * @set1: the first NodeSet or NULL
3855 * @set2: the second NodeSet
3856 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3857 *
3858 * Merges two nodesets, all nodes from @set2 are added to @set1
3859 * if @set1 is NULL, a new set is created and copied from @set2.
3860 * Checks for duplicate nodes. Clears set2.
3861 *
3862 * Returns @set1 once extended or NULL in case of error.
3863 */
3864static xmlNodeSetPtr
3865xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3866 int hasNullEntries)
3867{
3868 if ((set1 == NULL) && (hasNullEntries == 0)) {
3869 /*
3870 * Note that doing a memcpy of the list, namespace nodes are
3871 * just assigned to set1, since set2 is cleared anyway.
3872 */
3873 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3874 if (set1 == NULL)
3875 return(NULL);
3876 if (set2->nodeNr != 0) {
3877 memcpy(set1->nodeTab, set2->nodeTab,
3878 set2->nodeNr * sizeof(xmlNodePtr));
3879 set1->nodeNr = set2->nodeNr;
3880 }
3881 } else {
3882 int i, j, initNbSet1;
3883 xmlNodePtr n1, n2;
3884
3885 if (set1 == NULL)
Daniel Veillardf88d8492008-04-01 08:00:31 +00003886 set1 = xmlXPathNodeSetCreate(NULL);
3887 if (set1 == NULL)
3888 return (NULL);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003889
Daniel Veillard45490ae2008-07-29 09:13:19 +00003890 initNbSet1 = set1->nodeNr;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003891 for (i = 0;i < set2->nodeNr;i++) {
3892 n2 = set2->nodeTab[i];
3893 /*
3894 * Skip NULLed entries.
3895 */
3896 if (n2 == NULL)
3897 continue;
3898 /*
3899 * Skip duplicates.
3900 */
3901 for (j = 0; j < initNbSet1; j++) {
3902 n1 = set1->nodeTab[j];
Daniel Veillard45490ae2008-07-29 09:13:19 +00003903 if (n1 == n2) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003904 goto skip_node;
3905 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3906 (n2->type == XML_NAMESPACE_DECL))
Daniel Veillard45490ae2008-07-29 09:13:19 +00003907 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003908 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3909 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3910 ((xmlNsPtr) n2)->prefix)))
3911 {
3912 /*
3913 * Free the namespace node.
3914 */
3915 set2->nodeTab[i] = NULL;
3916 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3917 goto skip_node;
3918 }
3919 }
3920 }
3921 /*
3922 * grow the nodeTab if needed
3923 */
3924 if (set1->nodeMax == 0) {
3925 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3926 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3927 if (set1->nodeTab == NULL) {
3928 xmlXPathErrMemory(NULL, "merging nodeset\n");
3929 return(NULL);
3930 }
3931 memset(set1->nodeTab, 0,
3932 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3933 set1->nodeMax = XML_NODESET_DEFAULT;
3934 } else if (set1->nodeNr >= set1->nodeMax) {
3935 xmlNodePtr *temp;
Daniel Veillard45490ae2008-07-29 09:13:19 +00003936
Daniel Veillardcd852ad2012-07-30 10:12:18 +08003937 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3938 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3939 return(NULL);
3940 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003941 temp = (xmlNodePtr *) xmlRealloc(
Chris Evansd7958b22011-03-23 08:13:06 +08003942 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003943 if (temp == NULL) {
3944 xmlXPathErrMemory(NULL, "merging nodeset\n");
3945 return(NULL);
3946 }
3947 set1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08003948 set1->nodeMax *= 2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003949 }
3950 if (n2->type == XML_NAMESPACE_DECL) {
3951 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard45490ae2008-07-29 09:13:19 +00003952
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003953 set1->nodeTab[set1->nodeNr++] =
3954 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3955 } else
3956 set1->nodeTab[set1->nodeNr++] = n2;
3957skip_node:
3958 {}
3959 }
3960 }
3961 set2->nodeNr = 0;
3962 return(set1);
3963}
3964
3965/**
3966 * xmlXPathNodeSetMergeAndClearNoDupls:
3967 * @set1: the first NodeSet or NULL
3968 * @set2: the second NodeSet
3969 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3970 *
3971 * Merges two nodesets, all nodes from @set2 are added to @set1
3972 * if @set1 is NULL, a new set is created and copied from @set2.
3973 * Doesn't chack for duplicate nodes. Clears set2.
3974 *
3975 * Returns @set1 once extended or NULL in case of error.
3976 */
3977static xmlNodeSetPtr
3978xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3979 int hasNullEntries)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003980{
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003981 if (set2 == NULL)
3982 return(set1);
3983 if ((set1 == NULL) && (hasNullEntries == 0)) {
3984 /*
3985 * Note that doing a memcpy of the list, namespace nodes are
3986 * just assigned to set1, since set2 is cleared anyway.
3987 */
3988 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3989 if (set1 == NULL)
3990 return(NULL);
3991 if (set2->nodeNr != 0) {
3992 memcpy(set1->nodeTab, set2->nodeTab,
3993 set2->nodeNr * sizeof(xmlNodePtr));
3994 set1->nodeNr = set2->nodeNr;
3995 }
3996 } else {
3997 int i;
3998 xmlNodePtr n2;
3999
4000 if (set1 == NULL)
4001 set1 = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004002 if (set1 == NULL)
4003 return (NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004004
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004005 for (i = 0;i < set2->nodeNr;i++) {
4006 n2 = set2->nodeTab[i];
4007 /*
4008 * Skip NULLed entries.
4009 */
4010 if (n2 == NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004011 continue;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004012 if (set1->nodeMax == 0) {
4013 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4014 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4015 if (set1->nodeTab == NULL) {
4016 xmlXPathErrMemory(NULL, "merging nodeset\n");
4017 return(NULL);
4018 }
4019 memset(set1->nodeTab, 0,
4020 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4021 set1->nodeMax = XML_NODESET_DEFAULT;
4022 } else if (set1->nodeNr >= set1->nodeMax) {
4023 xmlNodePtr *temp;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004024
Daniel Veillardcd852ad2012-07-30 10:12:18 +08004025 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4026 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4027 return(NULL);
4028 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004029 temp = (xmlNodePtr *) xmlRealloc(
Chris Evansd7958b22011-03-23 08:13:06 +08004030 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004031 if (temp == NULL) {
4032 xmlXPathErrMemory(NULL, "merging nodeset\n");
4033 return(NULL);
4034 }
4035 set1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08004036 set1->nodeMax *= 2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004037 }
4038 set1->nodeTab[set1->nodeNr++] = n2;
4039 }
4040 }
4041 set2->nodeNr = 0;
4042 return(set1);
4043}
Daniel Veillard75be0132002-03-13 10:03:35 +00004044
4045/**
Owen Taylor3473f882001-02-23 17:55:21 +00004046 * xmlXPathNodeSetDel:
4047 * @cur: the initial node set
4048 * @val: an xmlNodePtr
4049 *
4050 * Removes an xmlNodePtr from an existing NodeSet
4051 */
4052void
4053xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4054 int i;
4055
4056 if (cur == NULL) return;
4057 if (val == NULL) return;
4058
4059 /*
William M. Brack08171912003-12-29 02:52:11 +00004060 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00004061 */
4062 for (i = 0;i < cur->nodeNr;i++)
4063 if (cur->nodeTab[i] == val) break;
4064
William M. Brack08171912003-12-29 02:52:11 +00004065 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00004066#ifdef DEBUG
Daniel Veillard45490ae2008-07-29 09:13:19 +00004067 xmlGenericError(xmlGenericErrorContext,
Owen Taylor3473f882001-02-23 17:55:21 +00004068 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4069 val->name);
4070#endif
4071 return;
4072 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004073 if ((cur->nodeTab[i] != NULL) &&
4074 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4075 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004076 cur->nodeNr--;
4077 for (;i < cur->nodeNr;i++)
4078 cur->nodeTab[i] = cur->nodeTab[i + 1];
4079 cur->nodeTab[cur->nodeNr] = NULL;
4080}
4081
4082/**
4083 * xmlXPathNodeSetRemove:
4084 * @cur: the initial node set
4085 * @val: the index to remove
4086 *
4087 * Removes an entry from an existing NodeSet list.
4088 */
4089void
4090xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4091 if (cur == NULL) return;
4092 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004093 if ((cur->nodeTab[val] != NULL) &&
4094 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4095 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00004096 cur->nodeNr--;
4097 for (;val < cur->nodeNr;val++)
4098 cur->nodeTab[val] = cur->nodeTab[val + 1];
4099 cur->nodeTab[cur->nodeNr] = NULL;
4100}
4101
4102/**
4103 * xmlXPathFreeNodeSet:
4104 * @obj: the xmlNodeSetPtr to free
4105 *
4106 * Free the NodeSet compound (not the actual nodes !).
4107 */
4108void
4109xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4110 if (obj == NULL) return;
4111 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004112 int i;
4113
William M. Brack08171912003-12-29 02:52:11 +00004114 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004115 for (i = 0;i < obj->nodeNr;i++)
4116 if ((obj->nodeTab[i] != NULL) &&
4117 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4118 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004119 xmlFree(obj->nodeTab);
4120 }
Owen Taylor3473f882001-02-23 17:55:21 +00004121 xmlFree(obj);
4122}
4123
4124/**
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004125 * xmlXPathNodeSetClear:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004126 * @set: the node set to clear
Daniel Veillard45490ae2008-07-29 09:13:19 +00004127 *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004128 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4129 * are feed), but does *not* free the list itself. Sets the length of the
4130 * list to 0.
4131 */
4132static void
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004133xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4134{
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004135 if ((set == NULL) || (set->nodeNr <= 0))
4136 return;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004137 else if (hasNsNodes) {
4138 int i;
4139 xmlNodePtr node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004140
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004141 for (i = 0; i < set->nodeNr; i++) {
4142 node = set->nodeTab[i];
4143 if ((node != NULL) &&
4144 (node->type == XML_NAMESPACE_DECL))
4145 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004146 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004147 }
4148 set->nodeNr = 0;
4149}
4150
4151/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004152 * xmlXPathNodeSetClearFromPos:
4153 * @set: the node set to be cleared
4154 * @pos: the start position to clear from
Daniel Veillard45490ae2008-07-29 09:13:19 +00004155 *
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004156 * Clears the list from temporary XPath objects (e.g. namespace nodes
4157 * are feed) starting with the entry at @pos, but does *not* free the list
4158 * itself. Sets the length of the list to @pos.
4159 */
4160static void
4161xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4162{
4163 if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4164 return;
4165 else if ((hasNsNodes)) {
4166 int i;
4167 xmlNodePtr node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004168
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004169 for (i = pos; i < set->nodeNr; i++) {
4170 node = set->nodeTab[i];
4171 if ((node != NULL) &&
4172 (node->type == XML_NAMESPACE_DECL))
4173 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004174 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004175 }
4176 set->nodeNr = pos;
4177}
4178
4179/**
Owen Taylor3473f882001-02-23 17:55:21 +00004180 * xmlXPathFreeValueTree:
4181 * @obj: the xmlNodeSetPtr to free
4182 *
4183 * Free the NodeSet compound and the actual tree, this is different
4184 * from xmlXPathFreeNodeSet()
4185 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004186static void
Owen Taylor3473f882001-02-23 17:55:21 +00004187xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4188 int i;
4189
4190 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00004191
4192 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004193 for (i = 0;i < obj->nodeNr;i++) {
4194 if (obj->nodeTab[i] != NULL) {
4195 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4196 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4197 } else {
4198 xmlFreeNodeList(obj->nodeTab[i]);
4199 }
4200 }
4201 }
Owen Taylor3473f882001-02-23 17:55:21 +00004202 xmlFree(obj->nodeTab);
4203 }
Owen Taylor3473f882001-02-23 17:55:21 +00004204 xmlFree(obj);
4205}
4206
4207#if defined(DEBUG) || defined(DEBUG_STEP)
4208/**
4209 * xmlGenericErrorContextNodeSet:
4210 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00004211 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00004212 *
4213 * Quick display of a NodeSet
4214 */
4215void
4216xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4217 int i;
4218
4219 if (output == NULL) output = xmlGenericErrorContext;
4220 if (obj == NULL) {
4221 fprintf(output, "NodeSet == NULL !\n");
4222 return;
4223 }
4224 if (obj->nodeNr == 0) {
4225 fprintf(output, "NodeSet is empty\n");
4226 return;
4227 }
4228 if (obj->nodeTab == NULL) {
4229 fprintf(output, " nodeTab == NULL !\n");
4230 return;
4231 }
4232 for (i = 0; i < obj->nodeNr; i++) {
4233 if (obj->nodeTab[i] == NULL) {
4234 fprintf(output, " NULL !\n");
4235 return;
4236 }
4237 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4238 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4239 fprintf(output, " /");
4240 else if (obj->nodeTab[i]->name == NULL)
4241 fprintf(output, " noname!");
4242 else fprintf(output, " %s", obj->nodeTab[i]->name);
4243 }
4244 fprintf(output, "\n");
4245}
4246#endif
4247
4248/**
4249 * xmlXPathNewNodeSet:
4250 * @val: the NodePtr value
4251 *
4252 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4253 * it with the single Node @val
4254 *
4255 * Returns the newly created object.
4256 */
4257xmlXPathObjectPtr
4258xmlXPathNewNodeSet(xmlNodePtr val) {
4259 xmlXPathObjectPtr ret;
4260
4261 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4262 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004263 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004264 return(NULL);
4265 }
4266 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4267 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00004268 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004269 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00004270 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004271#ifdef XP_DEBUG_OBJ_USAGE
4272 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4273#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004274 return(ret);
4275}
4276
4277/**
4278 * xmlXPathNewValueTree:
4279 * @val: the NodePtr value
4280 *
4281 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4282 * it with the tree root @val
4283 *
4284 * Returns the newly created object.
4285 */
4286xmlXPathObjectPtr
4287xmlXPathNewValueTree(xmlNodePtr val) {
4288 xmlXPathObjectPtr ret;
4289
4290 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4291 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004292 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004293 return(NULL);
4294 }
4295 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4296 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00004297 ret->boolval = 1;
4298 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00004299 ret->nodesetval = xmlXPathNodeSetCreate(val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004300#ifdef XP_DEBUG_OBJ_USAGE
4301 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4302#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004303 return(ret);
4304}
4305
4306/**
4307 * xmlXPathNewNodeSetList:
4308 * @val: an existing NodeSet
4309 *
4310 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4311 * it with the Nodeset @val
4312 *
4313 * Returns the newly created object.
4314 */
4315xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004316xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4317{
Owen Taylor3473f882001-02-23 17:55:21 +00004318 xmlXPathObjectPtr ret;
4319 int i;
4320
4321 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004322 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00004323 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004324 ret = xmlXPathNewNodeSet(NULL);
4325 else {
4326 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004327 if (ret)
4328 for (i = 1; i < val->nodeNr; ++i)
4329 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004330 }
Owen Taylor3473f882001-02-23 17:55:21 +00004331
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004332 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004333}
4334
4335/**
4336 * xmlXPathWrapNodeSet:
4337 * @val: the NodePtr value
4338 *
4339 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4340 *
4341 * Returns the newly created object.
4342 */
4343xmlXPathObjectPtr
4344xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4345 xmlXPathObjectPtr ret;
4346
4347 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4348 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004349 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004350 return(NULL);
4351 }
4352 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4353 ret->type = XPATH_NODESET;
4354 ret->nodesetval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004355#ifdef XP_DEBUG_OBJ_USAGE
4356 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4357#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004358 return(ret);
4359}
4360
4361/**
4362 * xmlXPathFreeNodeSetList:
4363 * @obj: an existing NodeSetList object
4364 *
4365 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4366 * the list contrary to xmlXPathFreeObject().
4367 */
4368void
4369xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4370 if (obj == NULL) return;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004371#ifdef XP_DEBUG_OBJ_USAGE
4372 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4373#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004374 xmlFree(obj);
4375}
4376
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004377/**
4378 * xmlXPathDifference:
4379 * @nodes1: a node-set
4380 * @nodes2: a node-set
4381 *
4382 * Implements the EXSLT - Sets difference() function:
4383 * node-set set:difference (node-set, node-set)
4384 *
4385 * Returns the difference between the two node sets, or nodes1 if
4386 * nodes2 is empty
4387 */
4388xmlNodeSetPtr
4389xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4390 xmlNodeSetPtr ret;
4391 int i, l1;
4392 xmlNodePtr cur;
4393
4394 if (xmlXPathNodeSetIsEmpty(nodes2))
4395 return(nodes1);
4396
4397 ret = xmlXPathNodeSetCreate(NULL);
4398 if (xmlXPathNodeSetIsEmpty(nodes1))
4399 return(ret);
4400
4401 l1 = xmlXPathNodeSetGetLength(nodes1);
4402
4403 for (i = 0; i < l1; i++) {
4404 cur = xmlXPathNodeSetItem(nodes1, i);
4405 if (!xmlXPathNodeSetContains(nodes2, cur))
4406 xmlXPathNodeSetAddUnique(ret, cur);
4407 }
4408 return(ret);
4409}
4410
4411/**
4412 * xmlXPathIntersection:
4413 * @nodes1: a node-set
4414 * @nodes2: a node-set
4415 *
4416 * Implements the EXSLT - Sets intersection() function:
4417 * node-set set:intersection (node-set, node-set)
4418 *
4419 * Returns a node set comprising the nodes that are within both the
4420 * node sets passed as arguments
4421 */
4422xmlNodeSetPtr
4423xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4424 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4425 int i, l1;
4426 xmlNodePtr cur;
4427
Daniel Veillardf88d8492008-04-01 08:00:31 +00004428 if (ret == NULL)
4429 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004430 if (xmlXPathNodeSetIsEmpty(nodes1))
4431 return(ret);
4432 if (xmlXPathNodeSetIsEmpty(nodes2))
4433 return(ret);
4434
4435 l1 = xmlXPathNodeSetGetLength(nodes1);
4436
4437 for (i = 0; i < l1; i++) {
4438 cur = xmlXPathNodeSetItem(nodes1, i);
4439 if (xmlXPathNodeSetContains(nodes2, cur))
4440 xmlXPathNodeSetAddUnique(ret, cur);
4441 }
4442 return(ret);
4443}
4444
4445/**
4446 * xmlXPathDistinctSorted:
4447 * @nodes: a node-set, sorted by document order
4448 *
4449 * Implements the EXSLT - Sets distinct() function:
4450 * node-set set:distinct (node-set)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004451 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004452 * Returns a subset of the nodes contained in @nodes, or @nodes if
4453 * it is empty
4454 */
4455xmlNodeSetPtr
4456xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4457 xmlNodeSetPtr ret;
4458 xmlHashTablePtr hash;
4459 int i, l;
4460 xmlChar * strval;
4461 xmlNodePtr cur;
4462
4463 if (xmlXPathNodeSetIsEmpty(nodes))
4464 return(nodes);
4465
4466 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004467 if (ret == NULL)
4468 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004469 l = xmlXPathNodeSetGetLength(nodes);
4470 hash = xmlHashCreate (l);
4471 for (i = 0; i < l; i++) {
4472 cur = xmlXPathNodeSetItem(nodes, i);
4473 strval = xmlXPathCastNodeToString(cur);
4474 if (xmlHashLookup(hash, strval) == NULL) {
4475 xmlHashAddEntry(hash, strval, strval);
4476 xmlXPathNodeSetAddUnique(ret, cur);
4477 } else {
4478 xmlFree(strval);
4479 }
4480 }
4481 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4482 return(ret);
4483}
4484
4485/**
4486 * xmlXPathDistinct:
4487 * @nodes: a node-set
4488 *
4489 * Implements the EXSLT - Sets distinct() function:
4490 * node-set set:distinct (node-set)
4491 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4492 * is called with the sorted node-set
4493 *
4494 * Returns a subset of the nodes contained in @nodes, or @nodes if
4495 * it is empty
4496 */
4497xmlNodeSetPtr
4498xmlXPathDistinct (xmlNodeSetPtr nodes) {
4499 if (xmlXPathNodeSetIsEmpty(nodes))
4500 return(nodes);
4501
4502 xmlXPathNodeSetSort(nodes);
4503 return(xmlXPathDistinctSorted(nodes));
4504}
4505
4506/**
4507 * xmlXPathHasSameNodes:
4508 * @nodes1: a node-set
4509 * @nodes2: a node-set
4510 *
4511 * Implements the EXSLT - Sets has-same-nodes function:
4512 * boolean set:has-same-node(node-set, node-set)
4513 *
4514 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4515 * otherwise
4516 */
4517int
4518xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4519 int i, l;
4520 xmlNodePtr cur;
4521
4522 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4523 xmlXPathNodeSetIsEmpty(nodes2))
4524 return(0);
4525
4526 l = xmlXPathNodeSetGetLength(nodes1);
4527 for (i = 0; i < l; i++) {
4528 cur = xmlXPathNodeSetItem(nodes1, i);
4529 if (xmlXPathNodeSetContains(nodes2, cur))
4530 return(1);
4531 }
4532 return(0);
4533}
4534
4535/**
4536 * xmlXPathNodeLeadingSorted:
4537 * @nodes: a node-set, sorted by document order
4538 * @node: a node
4539 *
4540 * Implements the EXSLT - Sets leading() function:
4541 * node-set set:leading (node-set, node-set)
4542 *
4543 * Returns the nodes in @nodes that precede @node in document order,
4544 * @nodes if @node is NULL or an empty node-set if @nodes
4545 * doesn't contain @node
4546 */
4547xmlNodeSetPtr
4548xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4549 int i, l;
4550 xmlNodePtr cur;
4551 xmlNodeSetPtr ret;
4552
4553 if (node == NULL)
4554 return(nodes);
4555
4556 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004557 if (ret == NULL)
4558 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004559 if (xmlXPathNodeSetIsEmpty(nodes) ||
4560 (!xmlXPathNodeSetContains(nodes, node)))
4561 return(ret);
4562
4563 l = xmlXPathNodeSetGetLength(nodes);
4564 for (i = 0; i < l; i++) {
4565 cur = xmlXPathNodeSetItem(nodes, i);
4566 if (cur == node)
4567 break;
4568 xmlXPathNodeSetAddUnique(ret, cur);
4569 }
4570 return(ret);
4571}
4572
4573/**
4574 * xmlXPathNodeLeading:
4575 * @nodes: a node-set
4576 * @node: a node
4577 *
4578 * Implements the EXSLT - Sets leading() function:
4579 * node-set set:leading (node-set, node-set)
4580 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4581 * is called.
4582 *
4583 * Returns the nodes in @nodes that precede @node in document order,
4584 * @nodes if @node is NULL or an empty node-set if @nodes
4585 * doesn't contain @node
4586 */
4587xmlNodeSetPtr
4588xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4589 xmlXPathNodeSetSort(nodes);
4590 return(xmlXPathNodeLeadingSorted(nodes, node));
4591}
4592
4593/**
4594 * xmlXPathLeadingSorted:
4595 * @nodes1: a node-set, sorted by document order
4596 * @nodes2: a node-set, sorted by document order
4597 *
4598 * Implements the EXSLT - Sets leading() function:
4599 * node-set set:leading (node-set, node-set)
4600 *
4601 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4602 * in document order, @nodes1 if @nodes2 is NULL or empty or
4603 * an empty node-set if @nodes1 doesn't contain @nodes2
4604 */
4605xmlNodeSetPtr
4606xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4607 if (xmlXPathNodeSetIsEmpty(nodes2))
4608 return(nodes1);
4609 return(xmlXPathNodeLeadingSorted(nodes1,
4610 xmlXPathNodeSetItem(nodes2, 1)));
4611}
4612
4613/**
4614 * xmlXPathLeading:
4615 * @nodes1: a node-set
4616 * @nodes2: a node-set
4617 *
4618 * Implements the EXSLT - Sets leading() function:
4619 * node-set set:leading (node-set, node-set)
4620 * @nodes1 and @nodes2 are sorted by document order, then
4621 * #exslSetsLeadingSorted is called.
4622 *
4623 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4624 * in document order, @nodes1 if @nodes2 is NULL or empty or
4625 * an empty node-set if @nodes1 doesn't contain @nodes2
4626 */
4627xmlNodeSetPtr
4628xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4629 if (xmlXPathNodeSetIsEmpty(nodes2))
4630 return(nodes1);
4631 if (xmlXPathNodeSetIsEmpty(nodes1))
4632 return(xmlXPathNodeSetCreate(NULL));
4633 xmlXPathNodeSetSort(nodes1);
4634 xmlXPathNodeSetSort(nodes2);
4635 return(xmlXPathNodeLeadingSorted(nodes1,
4636 xmlXPathNodeSetItem(nodes2, 1)));
4637}
4638
4639/**
4640 * xmlXPathNodeTrailingSorted:
4641 * @nodes: a node-set, sorted by document order
4642 * @node: a node
4643 *
4644 * Implements the EXSLT - Sets trailing() function:
4645 * node-set set:trailing (node-set, node-set)
4646 *
4647 * Returns the nodes in @nodes that follow @node in document order,
4648 * @nodes if @node is NULL or an empty node-set if @nodes
4649 * doesn't contain @node
4650 */
4651xmlNodeSetPtr
4652xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4653 int i, l;
4654 xmlNodePtr cur;
4655 xmlNodeSetPtr ret;
4656
4657 if (node == NULL)
4658 return(nodes);
4659
4660 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004661 if (ret == NULL)
4662 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004663 if (xmlXPathNodeSetIsEmpty(nodes) ||
4664 (!xmlXPathNodeSetContains(nodes, node)))
4665 return(ret);
4666
4667 l = xmlXPathNodeSetGetLength(nodes);
William M. Brack97ac8192007-06-06 17:19:24 +00004668 for (i = l - 1; i >= 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004669 cur = xmlXPathNodeSetItem(nodes, i);
4670 if (cur == node)
4671 break;
4672 xmlXPathNodeSetAddUnique(ret, cur);
4673 }
William M. Brack97ac8192007-06-06 17:19:24 +00004674 xmlXPathNodeSetSort(ret); /* bug 413451 */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004675 return(ret);
4676}
4677
4678/**
4679 * xmlXPathNodeTrailing:
4680 * @nodes: a node-set
4681 * @node: a node
4682 *
4683 * Implements the EXSLT - Sets trailing() function:
4684 * node-set set:trailing (node-set, node-set)
4685 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4686 * is called.
4687 *
4688 * Returns the nodes in @nodes that follow @node in document order,
4689 * @nodes if @node is NULL or an empty node-set if @nodes
4690 * doesn't contain @node
4691 */
4692xmlNodeSetPtr
4693xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4694 xmlXPathNodeSetSort(nodes);
4695 return(xmlXPathNodeTrailingSorted(nodes, node));
4696}
4697
4698/**
4699 * xmlXPathTrailingSorted:
4700 * @nodes1: a node-set, sorted by document order
4701 * @nodes2: a node-set, sorted by document order
4702 *
4703 * Implements the EXSLT - Sets trailing() function:
4704 * node-set set:trailing (node-set, node-set)
4705 *
4706 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4707 * in document order, @nodes1 if @nodes2 is NULL or empty or
4708 * an empty node-set if @nodes1 doesn't contain @nodes2
4709 */
4710xmlNodeSetPtr
4711xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4712 if (xmlXPathNodeSetIsEmpty(nodes2))
4713 return(nodes1);
4714 return(xmlXPathNodeTrailingSorted(nodes1,
4715 xmlXPathNodeSetItem(nodes2, 0)));
4716}
4717
4718/**
4719 * xmlXPathTrailing:
4720 * @nodes1: a node-set
4721 * @nodes2: a node-set
4722 *
4723 * Implements the EXSLT - Sets trailing() function:
4724 * node-set set:trailing (node-set, node-set)
4725 * @nodes1 and @nodes2 are sorted by document order, then
4726 * #xmlXPathTrailingSorted is called.
4727 *
4728 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4729 * in document order, @nodes1 if @nodes2 is NULL or empty or
4730 * an empty node-set if @nodes1 doesn't contain @nodes2
4731 */
4732xmlNodeSetPtr
4733xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4734 if (xmlXPathNodeSetIsEmpty(nodes2))
4735 return(nodes1);
4736 if (xmlXPathNodeSetIsEmpty(nodes1))
4737 return(xmlXPathNodeSetCreate(NULL));
4738 xmlXPathNodeSetSort(nodes1);
4739 xmlXPathNodeSetSort(nodes2);
4740 return(xmlXPathNodeTrailingSorted(nodes1,
4741 xmlXPathNodeSetItem(nodes2, 0)));
4742}
4743
Owen Taylor3473f882001-02-23 17:55:21 +00004744/************************************************************************
4745 * *
4746 * Routines to handle extra functions *
4747 * *
4748 ************************************************************************/
4749
4750/**
4751 * xmlXPathRegisterFunc:
4752 * @ctxt: the XPath context
4753 * @name: the function name
4754 * @f: the function implementation or NULL
4755 *
4756 * Register a new function. If @f is NULL it unregisters the function
4757 *
4758 * Returns 0 in case of success, -1 in case of error
4759 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00004760int
Owen Taylor3473f882001-02-23 17:55:21 +00004761xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4762 xmlXPathFunction f) {
4763 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4764}
4765
4766/**
4767 * xmlXPathRegisterFuncNS:
4768 * @ctxt: the XPath context
4769 * @name: the function name
4770 * @ns_uri: the function namespace URI
4771 * @f: the function implementation or NULL
4772 *
4773 * Register a new function. If @f is NULL it unregisters the function
4774 *
4775 * Returns 0 in case of success, -1 in case of error
4776 */
4777int
4778xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4779 const xmlChar *ns_uri, xmlXPathFunction f) {
4780 if (ctxt == NULL)
4781 return(-1);
4782 if (name == NULL)
4783 return(-1);
4784
4785 if (ctxt->funcHash == NULL)
4786 ctxt->funcHash = xmlHashCreate(0);
4787 if (ctxt->funcHash == NULL)
4788 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004789 if (f == NULL)
4790 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
William M. Brackad0e67c2004-12-01 14:35:10 +00004791 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
Owen Taylor3473f882001-02-23 17:55:21 +00004792}
4793
4794/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00004795 * xmlXPathRegisterFuncLookup:
4796 * @ctxt: the XPath context
4797 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004798 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00004799 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004800 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00004801 */
4802void
4803xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4804 xmlXPathFuncLookupFunc f,
4805 void *funcCtxt) {
4806 if (ctxt == NULL)
4807 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004808 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004809 ctxt->funcLookupData = funcCtxt;
4810}
4811
4812/**
Owen Taylor3473f882001-02-23 17:55:21 +00004813 * xmlXPathFunctionLookup:
4814 * @ctxt: the XPath context
4815 * @name: the function name
4816 *
4817 * Search in the Function array of the context for the given
4818 * function.
4819 *
4820 * Returns the xmlXPathFunction or NULL if not found
4821 */
4822xmlXPathFunction
4823xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00004824 if (ctxt == NULL)
4825 return (NULL);
4826
4827 if (ctxt->funcLookupFunc != NULL) {
4828 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004829 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004830
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004831 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004832 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004833 if (ret != NULL)
4834 return(ret);
4835 }
Owen Taylor3473f882001-02-23 17:55:21 +00004836 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4837}
4838
4839/**
4840 * xmlXPathFunctionLookupNS:
4841 * @ctxt: the XPath context
4842 * @name: the function name
4843 * @ns_uri: the function namespace URI
4844 *
4845 * Search in the Function array of the context for the given
4846 * function.
4847 *
4848 * Returns the xmlXPathFunction or NULL if not found
4849 */
4850xmlXPathFunction
4851xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4852 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00004853 xmlXPathFunction ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004854
Owen Taylor3473f882001-02-23 17:55:21 +00004855 if (ctxt == NULL)
4856 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004857 if (name == NULL)
4858 return(NULL);
4859
Thomas Broyerba4ad322001-07-26 16:55:21 +00004860 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004861 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004862
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004863 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004864 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004865 if (ret != NULL)
4866 return(ret);
4867 }
4868
4869 if (ctxt->funcHash == NULL)
4870 return(NULL);
4871
William M. Brackad0e67c2004-12-01 14:35:10 +00004872 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4873 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004874}
4875
4876/**
4877 * xmlXPathRegisteredFuncsCleanup:
4878 * @ctxt: the XPath context
4879 *
4880 * Cleanup the XPath context data associated to registered functions
4881 */
4882void
4883xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4884 if (ctxt == NULL)
4885 return;
4886
4887 xmlHashFree(ctxt->funcHash, NULL);
4888 ctxt->funcHash = NULL;
4889}
4890
4891/************************************************************************
4892 * *
William M. Brack08171912003-12-29 02:52:11 +00004893 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00004894 * *
4895 ************************************************************************/
4896
4897/**
4898 * xmlXPathRegisterVariable:
4899 * @ctxt: the XPath context
4900 * @name: the variable name
4901 * @value: the variable value or NULL
4902 *
4903 * Register a new variable value. If @value is NULL it unregisters
4904 * the variable
4905 *
4906 * Returns 0 in case of success, -1 in case of error
4907 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00004908int
Owen Taylor3473f882001-02-23 17:55:21 +00004909xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4910 xmlXPathObjectPtr value) {
4911 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4912}
4913
4914/**
4915 * xmlXPathRegisterVariableNS:
4916 * @ctxt: the XPath context
4917 * @name: the variable name
4918 * @ns_uri: the variable namespace URI
4919 * @value: the variable value or NULL
4920 *
4921 * Register a new variable value. If @value is NULL it unregisters
4922 * the variable
4923 *
4924 * Returns 0 in case of success, -1 in case of error
4925 */
4926int
4927xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4928 const xmlChar *ns_uri,
4929 xmlXPathObjectPtr value) {
4930 if (ctxt == NULL)
4931 return(-1);
4932 if (name == NULL)
4933 return(-1);
4934
4935 if (ctxt->varHash == NULL)
4936 ctxt->varHash = xmlHashCreate(0);
4937 if (ctxt->varHash == NULL)
4938 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004939 if (value == NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004940 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
Daniel Veillard94394cd2003-10-29 17:07:51 +00004941 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00004942 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4943 (void *) value,
4944 (xmlHashDeallocator)xmlXPathFreeObject));
4945}
4946
4947/**
4948 * xmlXPathRegisterVariableLookup:
4949 * @ctxt: the XPath context
4950 * @f: the lookup function
4951 * @data: the lookup data
4952 *
4953 * register an external mechanism to do variable lookup
4954 */
4955void
4956xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4957 xmlXPathVariableLookupFunc f, void *data) {
4958 if (ctxt == NULL)
4959 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004960 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00004961 ctxt->varLookupData = data;
4962}
4963
4964/**
4965 * xmlXPathVariableLookup:
4966 * @ctxt: the XPath context
4967 * @name: the variable name
4968 *
4969 * Search in the Variable array of the context for the given
4970 * variable value.
4971 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00004972 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00004973 */
4974xmlXPathObjectPtr
4975xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4976 if (ctxt == NULL)
4977 return(NULL);
4978
4979 if (ctxt->varLookupFunc != NULL) {
4980 xmlXPathObjectPtr ret;
4981
4982 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4983 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00004984 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004985 }
4986 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4987}
4988
4989/**
4990 * xmlXPathVariableLookupNS:
4991 * @ctxt: the XPath context
4992 * @name: the variable name
4993 * @ns_uri: the variable namespace URI
4994 *
4995 * Search in the Variable array of the context for the given
Daniel Veillard45490ae2008-07-29 09:13:19 +00004996 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00004997 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00004998 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00004999 */
5000xmlXPathObjectPtr
5001xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5002 const xmlChar *ns_uri) {
5003 if (ctxt == NULL)
5004 return(NULL);
5005
5006 if (ctxt->varLookupFunc != NULL) {
5007 xmlXPathObjectPtr ret;
5008
5009 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5010 (ctxt->varLookupData, name, ns_uri);
5011 if (ret != NULL) return(ret);
5012 }
5013
5014 if (ctxt->varHash == NULL)
5015 return(NULL);
5016 if (name == NULL)
5017 return(NULL);
5018
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005019 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
Daniel Veillard8c357d52001-07-03 23:43:33 +00005020 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00005021}
5022
5023/**
5024 * xmlXPathRegisteredVariablesCleanup:
5025 * @ctxt: the XPath context
5026 *
5027 * Cleanup the XPath context data associated to registered variables
5028 */
5029void
5030xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5031 if (ctxt == NULL)
5032 return;
5033
Daniel Veillard76d66f42001-05-16 21:05:17 +00005034 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00005035 ctxt->varHash = NULL;
5036}
5037
5038/**
5039 * xmlXPathRegisterNs:
5040 * @ctxt: the XPath context
Daniel Veillarddb3ce962009-03-25 09:43:49 +00005041 * @prefix: the namespace prefix cannot be NULL or empty string
Owen Taylor3473f882001-02-23 17:55:21 +00005042 * @ns_uri: the namespace name
5043 *
5044 * Register a new namespace. If @ns_uri is NULL it unregisters
5045 * the namespace
5046 *
5047 * Returns 0 in case of success, -1 in case of error
5048 */
5049int
5050xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5051 const xmlChar *ns_uri) {
5052 if (ctxt == NULL)
5053 return(-1);
5054 if (prefix == NULL)
5055 return(-1);
Daniel Veillarddb3ce962009-03-25 09:43:49 +00005056 if (prefix[0] == 0)
5057 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00005058
5059 if (ctxt->nsHash == NULL)
5060 ctxt->nsHash = xmlHashCreate(10);
5061 if (ctxt->nsHash == NULL)
5062 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00005063 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00005064 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00005065 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00005066 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00005067 (xmlHashDeallocator)xmlFree));
5068}
5069
5070/**
5071 * xmlXPathNsLookup:
5072 * @ctxt: the XPath context
5073 * @prefix: the namespace prefix value
5074 *
5075 * Search in the namespace declaration array of the context for the given
5076 * namespace name associated to the given prefix
5077 *
5078 * Returns the value or NULL if not found
5079 */
5080const xmlChar *
5081xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5082 if (ctxt == NULL)
5083 return(NULL);
5084 if (prefix == NULL)
5085 return(NULL);
5086
5087#ifdef XML_XML_NAMESPACE
5088 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5089 return(XML_XML_NAMESPACE);
5090#endif
5091
Daniel Veillardc8f620b2001-04-30 20:31:33 +00005092 if (ctxt->namespaces != NULL) {
5093 int i;
5094
5095 for (i = 0;i < ctxt->nsNr;i++) {
5096 if ((ctxt->namespaces[i] != NULL) &&
5097 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5098 return(ctxt->namespaces[i]->href);
5099 }
5100 }
Owen Taylor3473f882001-02-23 17:55:21 +00005101
5102 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5103}
5104
5105/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005106 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00005107 * @ctxt: the XPath context
5108 *
5109 * Cleanup the XPath context data associated to registered variables
5110 */
5111void
5112xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5113 if (ctxt == NULL)
5114 return;
5115
Daniel Veillard42766c02002-08-22 20:52:17 +00005116 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00005117 ctxt->nsHash = NULL;
5118}
5119
5120/************************************************************************
5121 * *
5122 * Routines to handle Values *
5123 * *
5124 ************************************************************************/
5125
William M. Brack08171912003-12-29 02:52:11 +00005126/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005127
5128/**
5129 * xmlXPathNewFloat:
5130 * @val: the double value
5131 *
5132 * Create a new xmlXPathObjectPtr of type double and of value @val
5133 *
5134 * Returns the newly created object.
5135 */
5136xmlXPathObjectPtr
5137xmlXPathNewFloat(double val) {
5138 xmlXPathObjectPtr ret;
5139
5140 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5141 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005142 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005143 return(NULL);
5144 }
5145 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5146 ret->type = XPATH_NUMBER;
5147 ret->floatval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005148#ifdef XP_DEBUG_OBJ_USAGE
5149 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5150#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005151 return(ret);
5152}
5153
5154/**
5155 * xmlXPathNewBoolean:
5156 * @val: the boolean value
5157 *
5158 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5159 *
5160 * Returns the newly created object.
5161 */
5162xmlXPathObjectPtr
5163xmlXPathNewBoolean(int val) {
5164 xmlXPathObjectPtr ret;
5165
5166 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5167 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005168 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005169 return(NULL);
5170 }
5171 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5172 ret->type = XPATH_BOOLEAN;
5173 ret->boolval = (val != 0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005174#ifdef XP_DEBUG_OBJ_USAGE
5175 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5176#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005177 return(ret);
5178}
5179
5180/**
5181 * xmlXPathNewString:
5182 * @val: the xmlChar * value
5183 *
5184 * Create a new xmlXPathObjectPtr of type string and of value @val
5185 *
5186 * Returns the newly created object.
5187 */
5188xmlXPathObjectPtr
5189xmlXPathNewString(const xmlChar *val) {
5190 xmlXPathObjectPtr ret;
5191
5192 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5193 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005194 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005195 return(NULL);
5196 }
5197 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5198 ret->type = XPATH_STRING;
5199 if (val != NULL)
5200 ret->stringval = xmlStrdup(val);
5201 else
5202 ret->stringval = xmlStrdup((const xmlChar *)"");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005203#ifdef XP_DEBUG_OBJ_USAGE
5204 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5205#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005206 return(ret);
5207}
5208
5209/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005210 * xmlXPathWrapString:
5211 * @val: the xmlChar * value
5212 *
5213 * Wraps the @val string into an XPath object.
5214 *
5215 * Returns the newly created object.
5216 */
5217xmlXPathObjectPtr
5218xmlXPathWrapString (xmlChar *val) {
5219 xmlXPathObjectPtr ret;
5220
5221 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5222 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005223 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005224 return(NULL);
5225 }
5226 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5227 ret->type = XPATH_STRING;
5228 ret->stringval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005229#ifdef XP_DEBUG_OBJ_USAGE
5230 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5231#endif
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005232 return(ret);
5233}
5234
5235/**
Owen Taylor3473f882001-02-23 17:55:21 +00005236 * xmlXPathNewCString:
5237 * @val: the char * value
5238 *
5239 * Create a new xmlXPathObjectPtr of type string and of value @val
5240 *
5241 * Returns the newly created object.
5242 */
5243xmlXPathObjectPtr
5244xmlXPathNewCString(const char *val) {
5245 xmlXPathObjectPtr ret;
5246
5247 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5248 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005249 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005250 return(NULL);
5251 }
5252 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5253 ret->type = XPATH_STRING;
5254 ret->stringval = xmlStrdup(BAD_CAST val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005255#ifdef XP_DEBUG_OBJ_USAGE
5256 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5257#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005258 return(ret);
5259}
5260
5261/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005262 * xmlXPathWrapCString:
5263 * @val: the char * value
5264 *
5265 * Wraps a string into an XPath object.
5266 *
5267 * Returns the newly created object.
5268 */
5269xmlXPathObjectPtr
5270xmlXPathWrapCString (char * val) {
5271 return(xmlXPathWrapString((xmlChar *)(val)));
5272}
5273
5274/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005275 * xmlXPathWrapExternal:
5276 * @val: the user data
5277 *
5278 * Wraps the @val data into an XPath object.
5279 *
5280 * Returns the newly created object.
5281 */
5282xmlXPathObjectPtr
5283xmlXPathWrapExternal (void *val) {
5284 xmlXPathObjectPtr ret;
5285
5286 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5287 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005288 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005289 return(NULL);
5290 }
5291 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5292 ret->type = XPATH_USERS;
5293 ret->user = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005294#ifdef XP_DEBUG_OBJ_USAGE
5295 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5296#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005297 return(ret);
5298}
5299
5300/**
Owen Taylor3473f882001-02-23 17:55:21 +00005301 * xmlXPathObjectCopy:
5302 * @val: the original object
5303 *
5304 * allocate a new copy of a given object
5305 *
5306 * Returns the newly created object.
5307 */
5308xmlXPathObjectPtr
5309xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5310 xmlXPathObjectPtr ret;
5311
5312 if (val == NULL)
5313 return(NULL);
5314
5315 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5316 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005317 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005318 return(NULL);
5319 }
5320 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005321#ifdef XP_DEBUG_OBJ_USAGE
5322 xmlXPathDebugObjUsageRequested(NULL, val->type);
5323#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005324 switch (val->type) {
5325 case XPATH_BOOLEAN:
5326 case XPATH_NUMBER:
5327 case XPATH_POINT:
5328 case XPATH_RANGE:
5329 break;
5330 case XPATH_STRING:
5331 ret->stringval = xmlStrdup(val->stringval);
5332 break;
5333 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00005334#if 0
5335/*
5336 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5337 this previous handling is no longer correct, and can cause some serious
5338 problems (ref. bug 145547)
5339*/
Owen Taylor3473f882001-02-23 17:55:21 +00005340 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005341 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005342 xmlNodePtr cur, tmp;
5343 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005344
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005345 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005346 top = xmlNewDoc(NULL);
5347 top->name = (char *)
5348 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005349 ret->user = top;
5350 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005351 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005352 cur = val->nodesetval->nodeTab[0]->children;
5353 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005354 tmp = xmlDocCopyNode(cur, top, 1);
5355 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005356 cur = cur->next;
5357 }
5358 }
William M. Bracke9449c52004-07-11 14:41:20 +00005359
Daniel Veillard9adc0462003-03-24 18:39:54 +00005360 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005361 } else
Owen Taylor3473f882001-02-23 17:55:21 +00005362 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005363 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00005364 break;
William M. Bracke9449c52004-07-11 14:41:20 +00005365#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005366 case XPATH_NODESET:
5367 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005368 /* Do not deallocate the copied tree value */
5369 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005370 break;
5371 case XPATH_LOCATIONSET:
5372#ifdef LIBXML_XPTR_ENABLED
5373 {
5374 xmlLocationSetPtr loc = val->user;
5375 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5376 break;
5377 }
5378#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00005379 case XPATH_USERS:
5380 ret->user = val->user;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005381 break;
Thomas Broyer47334c02001-10-07 16:41:52 +00005382 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00005383 xmlGenericError(xmlGenericErrorContext,
5384 "xmlXPathObjectCopy: unsupported type %d\n",
5385 val->type);
5386 break;
5387 }
5388 return(ret);
5389}
5390
5391/**
5392 * xmlXPathFreeObject:
5393 * @obj: the object to free
5394 *
5395 * Free up an xmlXPathObjectPtr object.
5396 */
5397void
5398xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5399 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005400 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00005401 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00005402#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005403 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005404 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00005405 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00005406 } else
5407#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005408 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
William M. Bracke9449c52004-07-11 14:41:20 +00005409 if (obj->nodesetval != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00005410 xmlXPathFreeValueTree(obj->nodesetval);
Daniel Veillard77851712001-02-27 21:54:07 +00005411 } else {
5412 if (obj->nodesetval != NULL)
5413 xmlXPathFreeNodeSet(obj->nodesetval);
5414 }
Owen Taylor3473f882001-02-23 17:55:21 +00005415#ifdef LIBXML_XPTR_ENABLED
5416 } else if (obj->type == XPATH_LOCATIONSET) {
5417 if (obj->user != NULL)
5418 xmlXPtrFreeLocationSet(obj->user);
5419#endif
5420 } else if (obj->type == XPATH_STRING) {
5421 if (obj->stringval != NULL)
5422 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005423 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005424#ifdef XP_DEBUG_OBJ_USAGE
5425 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5426#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00005427 xmlFree(obj);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005428}
Owen Taylor3473f882001-02-23 17:55:21 +00005429
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005430/**
5431 * xmlXPathReleaseObject:
5432 * @obj: the xmlXPathObjectPtr to free or to cache
5433 *
5434 * Depending on the state of the cache this frees the given
5435 * XPath object or stores it in the cache.
5436 */
5437static void
5438xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5439{
5440#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5441 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5442 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5443
5444#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5445
5446 if (obj == NULL)
5447 return;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005448 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005449 xmlXPathFreeObject(obj);
Daniel Veillard45490ae2008-07-29 09:13:19 +00005450 } else {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005451 xmlXPathContextCachePtr cache =
5452 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005453
5454 switch (obj->type) {
5455 case XPATH_NODESET:
5456 case XPATH_XSLT_TREE:
5457 if (obj->nodesetval != NULL) {
5458 if (obj->boolval) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00005459 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005460 * It looks like the @boolval is used for
5461 * evaluation if this an XSLT Result Tree Fragment.
5462 * TODO: Check if this assumption is correct.
5463 */
5464 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5465 xmlXPathFreeValueTree(obj->nodesetval);
5466 obj->nodesetval = NULL;
5467 } else if ((obj->nodesetval->nodeMax <= 40) &&
5468 (XP_CACHE_WANTS(cache->nodesetObjs,
5469 cache->maxNodeset)))
5470 {
5471 XP_CACHE_ADD(cache->nodesetObjs, obj);
5472 goto obj_cached;
5473 } else {
5474 xmlXPathFreeNodeSet(obj->nodesetval);
5475 obj->nodesetval = NULL;
5476 }
5477 }
5478 break;
5479 case XPATH_STRING:
5480 if (obj->stringval != NULL)
5481 xmlFree(obj->stringval);
5482
5483 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5484 XP_CACHE_ADD(cache->stringObjs, obj);
5485 goto obj_cached;
5486 }
5487 break;
5488 case XPATH_BOOLEAN:
5489 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5490 XP_CACHE_ADD(cache->booleanObjs, obj);
5491 goto obj_cached;
5492 }
5493 break;
5494 case XPATH_NUMBER:
5495 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5496 XP_CACHE_ADD(cache->numberObjs, obj);
5497 goto obj_cached;
5498 }
5499 break;
5500#ifdef LIBXML_XPTR_ENABLED
5501 case XPATH_LOCATIONSET:
5502 if (obj->user != NULL) {
5503 xmlXPtrFreeLocationSet(obj->user);
5504 }
5505 goto free_obj;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005506#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005507 default:
5508 goto free_obj;
5509 }
5510
5511 /*
5512 * Fallback to adding to the misc-objects slot.
5513 */
5514 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5515 XP_CACHE_ADD(cache->miscObjs, obj);
5516 } else
5517 goto free_obj;
5518
5519obj_cached:
5520
5521#ifdef XP_DEBUG_OBJ_USAGE
5522 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5523#endif
5524
5525 if (obj->nodesetval != NULL) {
5526 xmlNodeSetPtr tmpset = obj->nodesetval;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005527
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005528 /*
5529 * TODO: Due to those nasty ns-nodes, we need to traverse
5530 * the list and free the ns-nodes.
5531 * URGENT TODO: Check if it's actually slowing things down.
5532 * Maybe we shouldn't try to preserve the list.
5533 */
5534 if (tmpset->nodeNr > 1) {
5535 int i;
5536 xmlNodePtr node;
5537
5538 for (i = 0; i < tmpset->nodeNr; i++) {
5539 node = tmpset->nodeTab[i];
5540 if ((node != NULL) &&
5541 (node->type == XML_NAMESPACE_DECL))
5542 {
5543 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5544 }
5545 }
5546 } else if (tmpset->nodeNr == 1) {
5547 if ((tmpset->nodeTab[0] != NULL) &&
5548 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5549 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
Daniel Veillard45490ae2008-07-29 09:13:19 +00005550 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005551 tmpset->nodeNr = 0;
5552 memset(obj, 0, sizeof(xmlXPathObject));
5553 obj->nodesetval = tmpset;
5554 } else
5555 memset(obj, 0, sizeof(xmlXPathObject));
5556
5557 return;
5558
5559free_obj:
5560 /*
5561 * Cache is full; free the object.
Daniel Veillard45490ae2008-07-29 09:13:19 +00005562 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005563 if (obj->nodesetval != NULL)
5564 xmlXPathFreeNodeSet(obj->nodesetval);
5565#ifdef XP_DEBUG_OBJ_USAGE
5566 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5567#endif
5568 xmlFree(obj);
5569 }
5570 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005571}
5572
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005573
5574/************************************************************************
5575 * *
5576 * Type Casting Routines *
5577 * *
5578 ************************************************************************/
5579
5580/**
5581 * xmlXPathCastBooleanToString:
5582 * @val: a boolean
5583 *
5584 * Converts a boolean to its string value.
5585 *
5586 * Returns a newly allocated string.
5587 */
5588xmlChar *
5589xmlXPathCastBooleanToString (int val) {
5590 xmlChar *ret;
5591 if (val)
5592 ret = xmlStrdup((const xmlChar *) "true");
5593 else
5594 ret = xmlStrdup((const xmlChar *) "false");
5595 return(ret);
5596}
5597
5598/**
5599 * xmlXPathCastNumberToString:
5600 * @val: a number
5601 *
5602 * Converts a number to its string value.
5603 *
5604 * Returns a newly allocated string.
5605 */
5606xmlChar *
5607xmlXPathCastNumberToString (double val) {
5608 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00005609 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005610 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005611 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005612 break;
5613 case -1:
5614 ret = xmlStrdup((const xmlChar *) "-Infinity");
5615 break;
5616 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00005617 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005618 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005619 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5620 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005621 } else {
5622 /* could be improved */
5623 char buf[100];
Daniel Veillard11ce4002006-03-10 00:36:23 +00005624 xmlXPathFormatNumber(val, buf, 99);
5625 buf[99] = 0;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005626 ret = xmlStrdup((const xmlChar *) buf);
5627 }
5628 }
5629 return(ret);
5630}
5631
5632/**
5633 * xmlXPathCastNodeToString:
5634 * @node: a node
5635 *
5636 * Converts a node to its string value.
5637 *
5638 * Returns a newly allocated string.
5639 */
5640xmlChar *
5641xmlXPathCastNodeToString (xmlNodePtr node) {
William M. Brackd611c882007-05-31 05:07:17 +00005642xmlChar *ret;
5643 if ((ret = xmlNodeGetContent(node)) == NULL)
5644 ret = xmlStrdup((const xmlChar *) "");
5645 return(ret);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005646}
5647
5648/**
5649 * xmlXPathCastNodeSetToString:
5650 * @ns: a node-set
5651 *
5652 * Converts a node-set to its string value.
5653 *
5654 * Returns a newly allocated string.
5655 */
5656xmlChar *
5657xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5658 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5659 return(xmlStrdup((const xmlChar *) ""));
5660
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00005661 if (ns->nodeNr > 1)
5662 xmlXPathNodeSetSort(ns);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005663 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5664}
5665
5666/**
5667 * xmlXPathCastToString:
5668 * @val: an XPath object
5669 *
5670 * Converts an existing object to its string() equivalent
5671 *
Kasimier T. Buchcik50128ad2006-08-15 13:04:07 +00005672 * Returns the allocated string value of the object, NULL in case of error.
Daniel Veillard45490ae2008-07-29 09:13:19 +00005673 * It's up to the caller to free the string memory with xmlFree().
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005674 */
5675xmlChar *
5676xmlXPathCastToString(xmlXPathObjectPtr val) {
5677 xmlChar *ret = NULL;
5678
5679 if (val == NULL)
5680 return(xmlStrdup((const xmlChar *) ""));
5681 switch (val->type) {
5682 case XPATH_UNDEFINED:
5683#ifdef DEBUG_EXPR
5684 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5685#endif
5686 ret = xmlStrdup((const xmlChar *) "");
5687 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005688 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005689 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005690 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5691 break;
5692 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00005693 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005694 case XPATH_BOOLEAN:
5695 ret = xmlXPathCastBooleanToString(val->boolval);
5696 break;
5697 case XPATH_NUMBER: {
5698 ret = xmlXPathCastNumberToString(val->floatval);
5699 break;
5700 }
5701 case XPATH_USERS:
5702 case XPATH_POINT:
5703 case XPATH_RANGE:
5704 case XPATH_LOCATIONSET:
5705 TODO
5706 ret = xmlStrdup((const xmlChar *) "");
5707 break;
5708 }
5709 return(ret);
5710}
5711
5712/**
5713 * xmlXPathConvertString:
5714 * @val: an XPath object
5715 *
5716 * Converts an existing object to its string() equivalent
5717 *
5718 * Returns the new object, the old one is freed (or the operation
5719 * is done directly on @val)
5720 */
5721xmlXPathObjectPtr
5722xmlXPathConvertString(xmlXPathObjectPtr val) {
5723 xmlChar *res = NULL;
5724
5725 if (val == NULL)
5726 return(xmlXPathNewCString(""));
5727
5728 switch (val->type) {
5729 case XPATH_UNDEFINED:
5730#ifdef DEBUG_EXPR
5731 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5732#endif
5733 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005734 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005735 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005736 res = xmlXPathCastNodeSetToString(val->nodesetval);
5737 break;
5738 case XPATH_STRING:
5739 return(val);
5740 case XPATH_BOOLEAN:
5741 res = xmlXPathCastBooleanToString(val->boolval);
5742 break;
5743 case XPATH_NUMBER:
5744 res = xmlXPathCastNumberToString(val->floatval);
5745 break;
5746 case XPATH_USERS:
5747 case XPATH_POINT:
5748 case XPATH_RANGE:
5749 case XPATH_LOCATIONSET:
5750 TODO;
5751 break;
5752 }
5753 xmlXPathFreeObject(val);
5754 if (res == NULL)
5755 return(xmlXPathNewCString(""));
5756 return(xmlXPathWrapString(res));
5757}
5758
5759/**
5760 * xmlXPathCastBooleanToNumber:
5761 * @val: a boolean
5762 *
5763 * Converts a boolean to its number value
5764 *
5765 * Returns the number value
5766 */
5767double
5768xmlXPathCastBooleanToNumber(int val) {
5769 if (val)
5770 return(1.0);
5771 return(0.0);
5772}
5773
5774/**
5775 * xmlXPathCastStringToNumber:
5776 * @val: a string
5777 *
5778 * Converts a string to its number value
5779 *
5780 * Returns the number value
5781 */
5782double
5783xmlXPathCastStringToNumber(const xmlChar * val) {
5784 return(xmlXPathStringEvalNumber(val));
5785}
5786
5787/**
5788 * xmlXPathCastNodeToNumber:
5789 * @node: a node
5790 *
5791 * Converts a node to its number value
5792 *
5793 * Returns the number value
5794 */
5795double
5796xmlXPathCastNodeToNumber (xmlNodePtr node) {
5797 xmlChar *strval;
5798 double ret;
5799
5800 if (node == NULL)
5801 return(xmlXPathNAN);
5802 strval = xmlXPathCastNodeToString(node);
5803 if (strval == NULL)
5804 return(xmlXPathNAN);
5805 ret = xmlXPathCastStringToNumber(strval);
5806 xmlFree(strval);
5807
5808 return(ret);
5809}
5810
5811/**
5812 * xmlXPathCastNodeSetToNumber:
5813 * @ns: a node-set
5814 *
5815 * Converts a node-set to its number value
5816 *
5817 * Returns the number value
5818 */
5819double
5820xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5821 xmlChar *str;
5822 double ret;
5823
5824 if (ns == NULL)
5825 return(xmlXPathNAN);
5826 str = xmlXPathCastNodeSetToString(ns);
5827 ret = xmlXPathCastStringToNumber(str);
5828 xmlFree(str);
5829 return(ret);
5830}
5831
5832/**
5833 * xmlXPathCastToNumber:
5834 * @val: an XPath object
5835 *
5836 * Converts an XPath object to its number value
5837 *
5838 * Returns the number value
5839 */
5840double
5841xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5842 double ret = 0.0;
5843
5844 if (val == NULL)
5845 return(xmlXPathNAN);
5846 switch (val->type) {
5847 case XPATH_UNDEFINED:
5848#ifdef DEGUB_EXPR
5849 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5850#endif
5851 ret = xmlXPathNAN;
5852 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005853 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005854 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005855 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5856 break;
5857 case XPATH_STRING:
5858 ret = xmlXPathCastStringToNumber(val->stringval);
5859 break;
5860 case XPATH_NUMBER:
5861 ret = val->floatval;
5862 break;
5863 case XPATH_BOOLEAN:
5864 ret = xmlXPathCastBooleanToNumber(val->boolval);
5865 break;
5866 case XPATH_USERS:
5867 case XPATH_POINT:
5868 case XPATH_RANGE:
5869 case XPATH_LOCATIONSET:
5870 TODO;
5871 ret = xmlXPathNAN;
5872 break;
5873 }
5874 return(ret);
5875}
5876
5877/**
5878 * xmlXPathConvertNumber:
5879 * @val: an XPath object
5880 *
5881 * Converts an existing object to its number() equivalent
5882 *
5883 * Returns the new object, the old one is freed (or the operation
5884 * is done directly on @val)
5885 */
5886xmlXPathObjectPtr
5887xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5888 xmlXPathObjectPtr ret;
5889
5890 if (val == NULL)
5891 return(xmlXPathNewFloat(0.0));
5892 if (val->type == XPATH_NUMBER)
5893 return(val);
5894 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5895 xmlXPathFreeObject(val);
5896 return(ret);
5897}
5898
5899/**
5900 * xmlXPathCastNumberToBoolean:
5901 * @val: a number
5902 *
5903 * Converts a number to its boolean value
5904 *
5905 * Returns the boolean value
5906 */
5907int
5908xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00005909 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005910 return(0);
5911 return(1);
5912}
5913
5914/**
5915 * xmlXPathCastStringToBoolean:
5916 * @val: a string
5917 *
5918 * Converts a string to its boolean value
5919 *
5920 * Returns the boolean value
5921 */
5922int
5923xmlXPathCastStringToBoolean (const xmlChar *val) {
5924 if ((val == NULL) || (xmlStrlen(val) == 0))
5925 return(0);
5926 return(1);
5927}
5928
5929/**
5930 * xmlXPathCastNodeSetToBoolean:
5931 * @ns: a node-set
5932 *
5933 * Converts a node-set to its boolean value
5934 *
5935 * Returns the boolean value
5936 */
5937int
5938xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5939 if ((ns == NULL) || (ns->nodeNr == 0))
5940 return(0);
5941 return(1);
5942}
5943
5944/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005945 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005946 * @val: an XPath object
5947 *
5948 * Converts an XPath object to its boolean value
5949 *
5950 * Returns the boolean value
5951 */
5952int
5953xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5954 int ret = 0;
5955
5956 if (val == NULL)
5957 return(0);
5958 switch (val->type) {
5959 case XPATH_UNDEFINED:
5960#ifdef DEBUG_EXPR
5961 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
5962#endif
5963 ret = 0;
5964 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005965 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005966 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005967 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5968 break;
5969 case XPATH_STRING:
5970 ret = xmlXPathCastStringToBoolean(val->stringval);
5971 break;
5972 case XPATH_NUMBER:
5973 ret = xmlXPathCastNumberToBoolean(val->floatval);
5974 break;
5975 case XPATH_BOOLEAN:
5976 ret = val->boolval;
5977 break;
5978 case XPATH_USERS:
5979 case XPATH_POINT:
5980 case XPATH_RANGE:
5981 case XPATH_LOCATIONSET:
5982 TODO;
5983 ret = 0;
5984 break;
5985 }
5986 return(ret);
5987}
5988
5989
5990/**
5991 * xmlXPathConvertBoolean:
5992 * @val: an XPath object
5993 *
5994 * Converts an existing object to its boolean() equivalent
5995 *
5996 * Returns the new object, the old one is freed (or the operation
5997 * is done directly on @val)
5998 */
5999xmlXPathObjectPtr
6000xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6001 xmlXPathObjectPtr ret;
6002
6003 if (val == NULL)
6004 return(xmlXPathNewBoolean(0));
6005 if (val->type == XPATH_BOOLEAN)
6006 return(val);
6007 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6008 xmlXPathFreeObject(val);
6009 return(ret);
6010}
6011
Owen Taylor3473f882001-02-23 17:55:21 +00006012/************************************************************************
6013 * *
6014 * Routines to handle XPath contexts *
6015 * *
6016 ************************************************************************/
6017
6018/**
6019 * xmlXPathNewContext:
6020 * @doc: the XML document
6021 *
6022 * Create a new xmlXPathContext
6023 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00006024 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00006025 */
6026xmlXPathContextPtr
6027xmlXPathNewContext(xmlDocPtr doc) {
6028 xmlXPathContextPtr ret;
6029
6030 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6031 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006032 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006033 return(NULL);
6034 }
6035 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6036 ret->doc = doc;
6037 ret->node = NULL;
6038
6039 ret->varHash = NULL;
6040
6041 ret->nb_types = 0;
6042 ret->max_types = 0;
6043 ret->types = NULL;
6044
6045 ret->funcHash = xmlHashCreate(0);
6046
6047 ret->nb_axis = 0;
6048 ret->max_axis = 0;
6049 ret->axis = NULL;
6050
6051 ret->nsHash = NULL;
6052 ret->user = NULL;
6053
6054 ret->contextSize = -1;
6055 ret->proximityPosition = -1;
6056
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006057#ifdef XP_DEFAULT_CACHE_ON
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006058 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006059 xmlXPathFreeContext(ret);
6060 return(NULL);
6061 }
6062#endif
6063
Daniel Veillard45490ae2008-07-29 09:13:19 +00006064 xmlXPathRegisterAllFunctions(ret);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006065
Owen Taylor3473f882001-02-23 17:55:21 +00006066 return(ret);
6067}
6068
6069/**
6070 * xmlXPathFreeContext:
6071 * @ctxt: the context to free
6072 *
6073 * Free up an xmlXPathContext
6074 */
6075void
6076xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006077 if (ctxt == NULL) return;
6078
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006079 if (ctxt->cache != NULL)
6080 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
Owen Taylor3473f882001-02-23 17:55:21 +00006081 xmlXPathRegisteredNsCleanup(ctxt);
6082 xmlXPathRegisteredFuncsCleanup(ctxt);
6083 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006084 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00006085 xmlFree(ctxt);
6086}
6087
6088/************************************************************************
6089 * *
6090 * Routines to handle XPath parser contexts *
6091 * *
6092 ************************************************************************/
6093
6094#define CHECK_CTXT(ctxt) \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006095 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00006096 __xmlRaiseError(NULL, NULL, NULL, \
6097 NULL, NULL, XML_FROM_XPATH, \
6098 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6099 __FILE__, __LINE__, \
6100 NULL, NULL, NULL, 0, 0, \
6101 "NULL context pointer\n"); \
6102 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00006103 } \
6104
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006105#define CHECK_CTXT_NEG(ctxt) \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006106 if (ctxt == NULL) { \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006107 __xmlRaiseError(NULL, NULL, NULL, \
6108 NULL, NULL, XML_FROM_XPATH, \
6109 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6110 __FILE__, __LINE__, \
6111 NULL, NULL, NULL, 0, 0, \
6112 "NULL context pointer\n"); \
6113 return(-1); \
6114 } \
6115
Owen Taylor3473f882001-02-23 17:55:21 +00006116
6117#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00006118 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006119 (ctxt->doc->children == NULL)) { \
Daniel Veillard57b25162004-11-06 14:50:18 +00006120 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00006121 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00006122 }
Owen Taylor3473f882001-02-23 17:55:21 +00006123
6124
6125/**
6126 * xmlXPathNewParserContext:
6127 * @str: the XPath expression
6128 * @ctxt: the XPath context
6129 *
6130 * Create a new xmlXPathParserContext
6131 *
6132 * Returns the xmlXPathParserContext just allocated.
6133 */
6134xmlXPathParserContextPtr
6135xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6136 xmlXPathParserContextPtr ret;
6137
6138 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6139 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006140 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006141 return(NULL);
6142 }
6143 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6144 ret->cur = ret->base = str;
6145 ret->context = ctxt;
6146
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006147 ret->comp = xmlXPathNewCompExpr();
6148 if (ret->comp == NULL) {
6149 xmlFree(ret->valueTab);
6150 xmlFree(ret);
6151 return(NULL);
6152 }
Daniel Veillard4773df22004-01-23 13:15:13 +00006153 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6154 ret->comp->dict = ctxt->dict;
6155 xmlDictReference(ret->comp->dict);
6156 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006157
6158 return(ret);
6159}
6160
6161/**
6162 * xmlXPathCompParserContext:
6163 * @comp: the XPath compiled expression
6164 * @ctxt: the XPath context
6165 *
6166 * Create a new xmlXPathParserContext when processing a compiled expression
6167 *
6168 * Returns the xmlXPathParserContext just allocated.
6169 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006170static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006171xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6172 xmlXPathParserContextPtr ret;
6173
6174 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6175 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006176 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006177 return(NULL);
6178 }
6179 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6180
Owen Taylor3473f882001-02-23 17:55:21 +00006181 /* Allocate the value stack */
Daniel Veillard45490ae2008-07-29 09:13:19 +00006182 ret->valueTab = (xmlXPathObjectPtr *)
Owen Taylor3473f882001-02-23 17:55:21 +00006183 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006184 if (ret->valueTab == NULL) {
6185 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006186 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006187 return(NULL);
6188 }
Owen Taylor3473f882001-02-23 17:55:21 +00006189 ret->valueNr = 0;
6190 ret->valueMax = 10;
6191 ret->value = NULL;
Daniel Veillardf5048b32011-08-18 17:10:13 +08006192 ret->valueFrame = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006193
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006194 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006195 ret->comp = comp;
6196
Owen Taylor3473f882001-02-23 17:55:21 +00006197 return(ret);
6198}
6199
6200/**
6201 * xmlXPathFreeParserContext:
6202 * @ctxt: the context to free
6203 *
6204 * Free up an xmlXPathParserContext
6205 */
6206void
6207xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6208 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006209 xmlFree(ctxt->valueTab);
6210 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00006211 if (ctxt->comp != NULL) {
6212#ifdef XPATH_STREAMING
6213 if (ctxt->comp->stream != NULL) {
6214 xmlFreePatternList(ctxt->comp->stream);
6215 ctxt->comp->stream = NULL;
6216 }
6217#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006218 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard56de87e2005-02-16 00:22:29 +00006219 }
Owen Taylor3473f882001-02-23 17:55:21 +00006220 xmlFree(ctxt);
6221}
6222
6223/************************************************************************
6224 * *
6225 * The implicit core function library *
6226 * *
6227 ************************************************************************/
6228
Owen Taylor3473f882001-02-23 17:55:21 +00006229/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006230 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00006231 * @node: a node pointer
6232 *
6233 * Function computing the beginning of the string value of the node,
6234 * used to speed up comparisons
6235 *
6236 * Returns an int usable as a hash
6237 */
6238static unsigned int
6239xmlXPathNodeValHash(xmlNodePtr node) {
6240 int len = 2;
6241 const xmlChar * string = NULL;
6242 xmlNodePtr tmp = NULL;
6243 unsigned int ret = 0;
6244
6245 if (node == NULL)
6246 return(0);
6247
Daniel Veillard9adc0462003-03-24 18:39:54 +00006248 if (node->type == XML_DOCUMENT_NODE) {
6249 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6250 if (tmp == NULL)
6251 node = node->children;
6252 else
6253 node = tmp;
6254
6255 if (node == NULL)
6256 return(0);
6257 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006258
6259 switch (node->type) {
6260 case XML_COMMENT_NODE:
6261 case XML_PI_NODE:
6262 case XML_CDATA_SECTION_NODE:
6263 case XML_TEXT_NODE:
6264 string = node->content;
6265 if (string == NULL)
6266 return(0);
6267 if (string[0] == 0)
6268 return(0);
6269 return(((unsigned int) string[0]) +
6270 (((unsigned int) string[1]) << 8));
6271 case XML_NAMESPACE_DECL:
6272 string = ((xmlNsPtr)node)->href;
6273 if (string == NULL)
6274 return(0);
6275 if (string[0] == 0)
6276 return(0);
6277 return(((unsigned int) string[0]) +
6278 (((unsigned int) string[1]) << 8));
6279 case XML_ATTRIBUTE_NODE:
6280 tmp = ((xmlAttrPtr) node)->children;
6281 break;
6282 case XML_ELEMENT_NODE:
6283 tmp = node->children;
6284 break;
6285 default:
6286 return(0);
6287 }
6288 while (tmp != NULL) {
6289 switch (tmp->type) {
6290 case XML_COMMENT_NODE:
6291 case XML_PI_NODE:
6292 case XML_CDATA_SECTION_NODE:
6293 case XML_TEXT_NODE:
6294 string = tmp->content;
6295 break;
6296 case XML_NAMESPACE_DECL:
6297 string = ((xmlNsPtr)tmp)->href;
6298 break;
6299 default:
6300 break;
6301 }
6302 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006303 if (len == 1) {
6304 return(ret + (((unsigned int) string[0]) << 8));
6305 }
6306 if (string[1] == 0) {
6307 len = 1;
6308 ret = (unsigned int) string[0];
6309 } else {
6310 return(((unsigned int) string[0]) +
6311 (((unsigned int) string[1]) << 8));
6312 }
6313 }
6314 /*
6315 * Skip to next node
6316 */
6317 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6318 if (tmp->children->type != XML_ENTITY_DECL) {
6319 tmp = tmp->children;
6320 continue;
6321 }
6322 }
6323 if (tmp == node)
6324 break;
6325
6326 if (tmp->next != NULL) {
6327 tmp = tmp->next;
6328 continue;
6329 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00006330
Daniel Veillardf06307e2001-07-03 10:35:50 +00006331 do {
6332 tmp = tmp->parent;
6333 if (tmp == NULL)
6334 break;
6335 if (tmp == node) {
6336 tmp = NULL;
6337 break;
6338 }
6339 if (tmp->next != NULL) {
6340 tmp = tmp->next;
6341 break;
6342 }
6343 } while (tmp != NULL);
6344 }
6345 return(ret);
6346}
6347
6348/**
6349 * xmlXPathStringHash:
6350 * @string: a string
6351 *
6352 * Function computing the beginning of the string value of the node,
6353 * used to speed up comparisons
6354 *
6355 * Returns an int usable as a hash
6356 */
6357static unsigned int
6358xmlXPathStringHash(const xmlChar * string) {
6359 if (string == NULL)
6360 return((unsigned int) 0);
6361 if (string[0] == 0)
6362 return(0);
6363 return(((unsigned int) string[0]) +
6364 (((unsigned int) string[1]) << 8));
6365}
6366
6367/**
Owen Taylor3473f882001-02-23 17:55:21 +00006368 * xmlXPathCompareNodeSetFloat:
6369 * @ctxt: the XPath Parser context
6370 * @inf: less than (1) or greater than (0)
6371 * @strict: is the comparison strict
6372 * @arg: the node set
6373 * @f: the value
6374 *
6375 * Implement the compare operation between a nodeset and a number
6376 * @ns < @val (1, 1, ...
6377 * @ns <= @val (1, 0, ...
6378 * @ns > @val (0, 1, ...
6379 * @ns >= @val (0, 0, ...
6380 *
6381 * If one object to be compared is a node-set and the other is a number,
6382 * then the comparison will be true if and only if there is a node in the
6383 * node-set such that the result of performing the comparison on the number
6384 * to be compared and on the result of converting the string-value of that
6385 * node to a number using the number function is true.
6386 *
6387 * Returns 0 or 1 depending on the results of the test.
6388 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006389static int
Owen Taylor3473f882001-02-23 17:55:21 +00006390xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6391 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6392 int i, ret = 0;
6393 xmlNodeSetPtr ns;
6394 xmlChar *str2;
6395
6396 if ((f == NULL) || (arg == NULL) ||
6397 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006398 xmlXPathReleaseObject(ctxt->context, arg);
6399 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006400 return(0);
6401 }
6402 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006403 if (ns != NULL) {
6404 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006405 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006406 if (str2 != NULL) {
6407 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006408 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006409 xmlFree(str2);
6410 xmlXPathNumberFunction(ctxt, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006411 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006412 ret = xmlXPathCompareValues(ctxt, inf, strict);
6413 if (ret)
6414 break;
6415 }
6416 }
Owen Taylor3473f882001-02-23 17:55:21 +00006417 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006418 xmlXPathReleaseObject(ctxt->context, arg);
6419 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006420 return(ret);
6421}
6422
6423/**
6424 * xmlXPathCompareNodeSetString:
6425 * @ctxt: the XPath Parser context
6426 * @inf: less than (1) or greater than (0)
6427 * @strict: is the comparison strict
6428 * @arg: the node set
6429 * @s: the value
6430 *
6431 * Implement the compare operation between a nodeset and a string
6432 * @ns < @val (1, 1, ...
6433 * @ns <= @val (1, 0, ...
6434 * @ns > @val (0, 1, ...
6435 * @ns >= @val (0, 0, ...
6436 *
6437 * If one object to be compared is a node-set and the other is a string,
6438 * then the comparison will be true if and only if there is a node in
6439 * the node-set such that the result of performing the comparison on the
6440 * string-value of the node and the other string is true.
6441 *
6442 * Returns 0 or 1 depending on the results of the test.
6443 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006444static int
Owen Taylor3473f882001-02-23 17:55:21 +00006445xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6446 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6447 int i, ret = 0;
6448 xmlNodeSetPtr ns;
6449 xmlChar *str2;
6450
6451 if ((s == NULL) || (arg == NULL) ||
6452 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006453 xmlXPathReleaseObject(ctxt->context, arg);
6454 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006455 return(0);
6456 }
6457 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006458 if (ns != NULL) {
6459 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006460 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006461 if (str2 != NULL) {
6462 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006463 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006464 xmlFree(str2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006465 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006466 ret = xmlXPathCompareValues(ctxt, inf, strict);
6467 if (ret)
6468 break;
6469 }
6470 }
Owen Taylor3473f882001-02-23 17:55:21 +00006471 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006472 xmlXPathReleaseObject(ctxt->context, arg);
6473 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006474 return(ret);
6475}
6476
6477/**
6478 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006479 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00006480 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006481 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00006482 * @arg2: the second node set object
6483 *
6484 * Implement the compare operation on nodesets:
6485 *
6486 * If both objects to be compared are node-sets, then the comparison
6487 * will be true if and only if there is a node in the first node-set
6488 * and a node in the second node-set such that the result of performing
Daniel Veillard45490ae2008-07-29 09:13:19 +00006489 * the comparison on the string-values of the two nodes is true.
Owen Taylor3473f882001-02-23 17:55:21 +00006490 * ....
6491 * When neither object to be compared is a node-set and the operator
6492 * is <=, <, >= or >, then the objects are compared by converting both
6493 * objects to numbers and comparing the numbers according to IEEE 754.
6494 * ....
6495 * The number function converts its argument to a number as follows:
6496 * - a string that consists of optional whitespace followed by an
6497 * optional minus sign followed by a Number followed by whitespace
6498 * is converted to the IEEE 754 number that is nearest (according
6499 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6500 * represented by the string; any other string is converted to NaN
6501 *
6502 * Conclusion all nodes need to be converted first to their string value
Daniel Veillard45490ae2008-07-29 09:13:19 +00006503 * and then the comparison must be done when possible
Owen Taylor3473f882001-02-23 17:55:21 +00006504 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006505static int
6506xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00006507 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6508 int i, j, init = 0;
6509 double val1;
6510 double *values2;
6511 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006512 xmlNodeSetPtr ns1;
6513 xmlNodeSetPtr ns2;
6514
6515 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006516 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6517 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006518 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006519 }
Owen Taylor3473f882001-02-23 17:55:21 +00006520 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006521 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6522 xmlXPathFreeObject(arg1);
6523 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006524 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006525 }
Owen Taylor3473f882001-02-23 17:55:21 +00006526
6527 ns1 = arg1->nodesetval;
6528 ns2 = arg2->nodesetval;
6529
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006530 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006531 xmlXPathFreeObject(arg1);
6532 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006533 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006534 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006535 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006536 xmlXPathFreeObject(arg1);
6537 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006538 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006539 }
Owen Taylor3473f882001-02-23 17:55:21 +00006540
6541 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6542 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006543 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00006544 xmlXPathFreeObject(arg1);
6545 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006546 return(0);
6547 }
6548 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006549 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00006550 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00006551 continue;
6552 for (j = 0;j < ns2->nodeNr;j++) {
6553 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006554 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00006555 }
Daniel Veillardcda96922001-08-21 10:56:31 +00006556 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00006557 continue;
Daniel Veillard45490ae2008-07-29 09:13:19 +00006558 if (inf && strict)
Owen Taylor3473f882001-02-23 17:55:21 +00006559 ret = (val1 < values2[j]);
6560 else if (inf && !strict)
6561 ret = (val1 <= values2[j]);
6562 else if (!inf && strict)
6563 ret = (val1 > values2[j]);
6564 else if (!inf && !strict)
6565 ret = (val1 >= values2[j]);
6566 if (ret)
6567 break;
6568 }
6569 if (ret)
6570 break;
6571 init = 1;
6572 }
6573 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006574 xmlXPathFreeObject(arg1);
6575 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006576 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006577}
6578
6579/**
6580 * xmlXPathCompareNodeSetValue:
6581 * @ctxt: the XPath Parser context
6582 * @inf: less than (1) or greater than (0)
6583 * @strict: is the comparison strict
6584 * @arg: the node set
6585 * @val: the value
6586 *
6587 * Implement the compare operation between a nodeset and a value
6588 * @ns < @val (1, 1, ...
6589 * @ns <= @val (1, 0, ...
6590 * @ns > @val (0, 1, ...
6591 * @ns >= @val (0, 0, ...
6592 *
6593 * If one object to be compared is a node-set and the other is a boolean,
6594 * then the comparison will be true if and only if the result of performing
6595 * the comparison on the boolean and on the result of converting
6596 * the node-set to a boolean using the boolean function is true.
6597 *
6598 * Returns 0 or 1 depending on the results of the test.
6599 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006600static int
Owen Taylor3473f882001-02-23 17:55:21 +00006601xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6602 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6603 if ((val == NULL) || (arg == NULL) ||
6604 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6605 return(0);
6606
6607 switch(val->type) {
6608 case XPATH_NUMBER:
6609 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6610 case XPATH_NODESET:
6611 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006612 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00006613 case XPATH_STRING:
6614 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6615 case XPATH_BOOLEAN:
6616 valuePush(ctxt, arg);
6617 xmlXPathBooleanFunction(ctxt, 1);
6618 valuePush(ctxt, val);
6619 return(xmlXPathCompareValues(ctxt, inf, strict));
6620 default:
6621 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00006622 }
6623 return(0);
6624}
6625
6626/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006627 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00006628 * @arg: the nodeset object argument
6629 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00006630 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006631 *
6632 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6633 * If one object to be compared is a node-set and the other is a string,
6634 * then the comparison will be true if and only if there is a node in
6635 * the node-set such that the result of performing the comparison on the
6636 * string-value of the node and the other string is true.
6637 *
6638 * Returns 0 or 1 depending on the results of the test.
6639 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006640static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006641xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006642{
Owen Taylor3473f882001-02-23 17:55:21 +00006643 int i;
6644 xmlNodeSetPtr ns;
6645 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006646 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00006647
6648 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00006649 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6650 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006651 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00006652 /*
6653 * A NULL nodeset compared with a string is always false
6654 * (since there is no node equal, and no node not equal)
6655 */
6656 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00006657 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00006658 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006659 for (i = 0; i < ns->nodeNr; i++) {
6660 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6661 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6662 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6663 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006664 if (neq)
6665 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006666 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00006667 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6668 if (neq)
6669 continue;
6670 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006671 } else if (neq) {
6672 if (str2 != NULL)
6673 xmlFree(str2);
6674 return (1);
6675 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006676 if (str2 != NULL)
6677 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006678 } else if (neq)
6679 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00006680 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006681 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006682}
6683
6684/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006685 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00006686 * @arg: the nodeset object argument
6687 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00006688 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006689 *
6690 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6691 * If one object to be compared is a node-set and the other is a number,
6692 * then the comparison will be true if and only if there is a node in
6693 * the node-set such that the result of performing the comparison on the
6694 * number to be compared and on the result of converting the string-value
6695 * of that node to a number using the number function is true.
6696 *
6697 * Returns 0 or 1 depending on the results of the test.
6698 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006699static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006700xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6701 xmlXPathObjectPtr arg, double f, int neq) {
6702 int i, ret=0;
6703 xmlNodeSetPtr ns;
6704 xmlChar *str2;
6705 xmlXPathObjectPtr val;
6706 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00006707
6708 if ((arg == NULL) ||
6709 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6710 return(0);
6711
William M. Brack0c022ad2002-07-12 00:56:01 +00006712 ns = arg->nodesetval;
6713 if (ns != NULL) {
6714 for (i=0;i<ns->nodeNr;i++) {
6715 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6716 if (str2 != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006717 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
William M. Brack0c022ad2002-07-12 00:56:01 +00006718 xmlFree(str2);
6719 xmlXPathNumberFunction(ctxt, 1);
6720 val = valuePop(ctxt);
6721 v = val->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006722 xmlXPathReleaseObject(ctxt->context, val);
William M. Brack0c022ad2002-07-12 00:56:01 +00006723 if (!xmlXPathIsNaN(v)) {
6724 if ((!neq) && (v==f)) {
6725 ret = 1;
6726 break;
6727 } else if ((neq) && (v!=f)) {
6728 ret = 1;
6729 break;
6730 }
William M. Brack32f0f712005-07-14 07:00:33 +00006731 } else { /* NaN is unequal to any value */
6732 if (neq)
6733 ret = 1;
William M. Brack0c022ad2002-07-12 00:56:01 +00006734 }
6735 }
6736 }
6737 }
6738
6739 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006740}
6741
6742
6743/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006744 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00006745 * @arg1: first nodeset object argument
6746 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00006747 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006748 *
William M. Brack0c022ad2002-07-12 00:56:01 +00006749 * Implement the equal / not equal operation on XPath nodesets:
6750 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00006751 * If both objects to be compared are node-sets, then the comparison
6752 * will be true if and only if there is a node in the first node-set and
6753 * a node in the second node-set such that the result of performing the
6754 * comparison on the string-values of the two nodes is true.
6755 *
6756 * (needless to say, this is a costly operation)
6757 *
6758 * Returns 0 or 1 depending on the results of the test.
6759 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006760static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006761xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00006762 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006763 unsigned int *hashs1;
6764 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00006765 xmlChar **values1;
6766 xmlChar **values2;
6767 int ret = 0;
6768 xmlNodeSetPtr ns1;
6769 xmlNodeSetPtr ns2;
6770
6771 if ((arg1 == NULL) ||
6772 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6773 return(0);
6774 if ((arg2 == NULL) ||
6775 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6776 return(0);
6777
6778 ns1 = arg1->nodesetval;
6779 ns2 = arg2->nodesetval;
6780
Daniel Veillard911f49a2001-04-07 15:39:35 +00006781 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006782 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006783 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006784 return(0);
6785
6786 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00006787 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00006788 */
William M. Brack0c022ad2002-07-12 00:56:01 +00006789 if (neq == 0)
6790 for (i = 0;i < ns1->nodeNr;i++)
6791 for (j = 0;j < ns2->nodeNr;j++)
6792 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6793 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006794
6795 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006796 if (values1 == NULL) {
6797 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006798 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006799 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006800 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6801 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006802 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006803 xmlFree(values1);
6804 return(0);
6805 }
Owen Taylor3473f882001-02-23 17:55:21 +00006806 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6807 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6808 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006809 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006810 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00006811 xmlFree(values1);
6812 return(0);
6813 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006814 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6815 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006816 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006817 xmlFree(hashs1);
6818 xmlFree(values1);
6819 xmlFree(values2);
6820 return(0);
6821 }
Owen Taylor3473f882001-02-23 17:55:21 +00006822 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6823 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006824 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006825 for (j = 0;j < ns2->nodeNr;j++) {
6826 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006827 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006828 if (hashs1[i] != hashs2[j]) {
6829 if (neq) {
6830 ret = 1;
6831 break;
6832 }
6833 }
6834 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006835 if (values1[i] == NULL)
6836 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6837 if (values2[j] == NULL)
6838 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006839 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006840 if (ret)
6841 break;
6842 }
Owen Taylor3473f882001-02-23 17:55:21 +00006843 }
6844 if (ret)
6845 break;
6846 }
6847 for (i = 0;i < ns1->nodeNr;i++)
6848 if (values1[i] != NULL)
6849 xmlFree(values1[i]);
6850 for (j = 0;j < ns2->nodeNr;j++)
6851 if (values2[j] != NULL)
6852 xmlFree(values2[j]);
6853 xmlFree(values1);
6854 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006855 xmlFree(hashs1);
6856 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00006857 return(ret);
6858}
6859
William M. Brack0c022ad2002-07-12 00:56:01 +00006860static int
6861xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6862 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00006863 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00006864 /*
6865 *At this point we are assured neither arg1 nor arg2
6866 *is a nodeset, so we can just pick the appropriate routine.
6867 */
Owen Taylor3473f882001-02-23 17:55:21 +00006868 switch (arg1->type) {
6869 case XPATH_UNDEFINED:
6870#ifdef DEBUG_EXPR
6871 xmlGenericError(xmlGenericErrorContext,
6872 "Equal: undefined\n");
6873#endif
6874 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006875 case XPATH_BOOLEAN:
6876 switch (arg2->type) {
6877 case XPATH_UNDEFINED:
6878#ifdef DEBUG_EXPR
6879 xmlGenericError(xmlGenericErrorContext,
6880 "Equal: undefined\n");
6881#endif
6882 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006883 case XPATH_BOOLEAN:
6884#ifdef DEBUG_EXPR
6885 xmlGenericError(xmlGenericErrorContext,
6886 "Equal: %d boolean %d \n",
6887 arg1->boolval, arg2->boolval);
6888#endif
6889 ret = (arg1->boolval == arg2->boolval);
6890 break;
6891 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00006892 ret = (arg1->boolval ==
6893 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006894 break;
6895 case XPATH_STRING:
6896 if ((arg2->stringval == NULL) ||
6897 (arg2->stringval[0] == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00006898 else
Owen Taylor3473f882001-02-23 17:55:21 +00006899 ret = 1;
6900 ret = (arg1->boolval == ret);
6901 break;
6902 case XPATH_USERS:
6903 case XPATH_POINT:
6904 case XPATH_RANGE:
6905 case XPATH_LOCATIONSET:
6906 TODO
6907 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006908 case XPATH_NODESET:
6909 case XPATH_XSLT_TREE:
6910 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006911 }
6912 break;
6913 case XPATH_NUMBER:
6914 switch (arg2->type) {
6915 case XPATH_UNDEFINED:
6916#ifdef DEBUG_EXPR
6917 xmlGenericError(xmlGenericErrorContext,
6918 "Equal: undefined\n");
6919#endif
6920 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006921 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00006922 ret = (arg2->boolval==
6923 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006924 break;
6925 case XPATH_STRING:
6926 valuePush(ctxt, arg2);
6927 xmlXPathNumberFunction(ctxt, 1);
6928 arg2 = valuePop(ctxt);
6929 /* no break on purpose */
6930 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006931 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00006932 if (xmlXPathIsNaN(arg1->floatval) ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00006933 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00006934 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006935 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6936 if (xmlXPathIsInf(arg2->floatval) == 1)
6937 ret = 1;
6938 else
6939 ret = 0;
6940 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6941 if (xmlXPathIsInf(arg2->floatval) == -1)
6942 ret = 1;
6943 else
6944 ret = 0;
6945 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6946 if (xmlXPathIsInf(arg1->floatval) == 1)
6947 ret = 1;
6948 else
6949 ret = 0;
6950 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6951 if (xmlXPathIsInf(arg1->floatval) == -1)
6952 ret = 1;
6953 else
6954 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00006955 } else {
6956 ret = (arg1->floatval == arg2->floatval);
6957 }
Owen Taylor3473f882001-02-23 17:55:21 +00006958 break;
6959 case XPATH_USERS:
6960 case XPATH_POINT:
6961 case XPATH_RANGE:
6962 case XPATH_LOCATIONSET:
6963 TODO
6964 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006965 case XPATH_NODESET:
6966 case XPATH_XSLT_TREE:
6967 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006968 }
6969 break;
6970 case XPATH_STRING:
6971 switch (arg2->type) {
6972 case XPATH_UNDEFINED:
6973#ifdef DEBUG_EXPR
6974 xmlGenericError(xmlGenericErrorContext,
6975 "Equal: undefined\n");
6976#endif
6977 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006978 case XPATH_BOOLEAN:
6979 if ((arg1->stringval == NULL) ||
6980 (arg1->stringval[0] == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00006981 else
Owen Taylor3473f882001-02-23 17:55:21 +00006982 ret = 1;
6983 ret = (arg2->boolval == ret);
6984 break;
6985 case XPATH_STRING:
6986 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6987 break;
6988 case XPATH_NUMBER:
6989 valuePush(ctxt, arg1);
6990 xmlXPathNumberFunction(ctxt, 1);
6991 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006992 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00006993 if (xmlXPathIsNaN(arg1->floatval) ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00006994 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00006995 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006996 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6997 if (xmlXPathIsInf(arg2->floatval) == 1)
6998 ret = 1;
6999 else
7000 ret = 0;
7001 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7002 if (xmlXPathIsInf(arg2->floatval) == -1)
7003 ret = 1;
7004 else
7005 ret = 0;
7006 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7007 if (xmlXPathIsInf(arg1->floatval) == 1)
7008 ret = 1;
7009 else
7010 ret = 0;
7011 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7012 if (xmlXPathIsInf(arg1->floatval) == -1)
7013 ret = 1;
7014 else
7015 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007016 } else {
7017 ret = (arg1->floatval == arg2->floatval);
7018 }
Owen Taylor3473f882001-02-23 17:55:21 +00007019 break;
7020 case XPATH_USERS:
7021 case XPATH_POINT:
7022 case XPATH_RANGE:
7023 case XPATH_LOCATIONSET:
7024 TODO
7025 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007026 case XPATH_NODESET:
7027 case XPATH_XSLT_TREE:
7028 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007029 }
7030 break;
7031 case XPATH_USERS:
7032 case XPATH_POINT:
7033 case XPATH_RANGE:
7034 case XPATH_LOCATIONSET:
7035 TODO
7036 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007037 case XPATH_NODESET:
7038 case XPATH_XSLT_TREE:
7039 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007040 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007041 xmlXPathReleaseObject(ctxt->context, arg1);
7042 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007043 return(ret);
7044}
7045
William M. Brack0c022ad2002-07-12 00:56:01 +00007046/**
7047 * xmlXPathEqualValues:
7048 * @ctxt: the XPath Parser context
7049 *
7050 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7051 *
7052 * Returns 0 or 1 depending on the results of the test.
7053 */
7054int
7055xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7056 xmlXPathObjectPtr arg1, arg2, argtmp;
7057 int ret = 0;
7058
Daniel Veillard6128c012004-11-08 17:16:15 +00007059 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007060 arg2 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007061 arg1 = valuePop(ctxt);
7062 if ((arg1 == NULL) || (arg2 == NULL)) {
7063 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007064 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007065 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007066 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007067 XP_ERROR0(XPATH_INVALID_OPERAND);
7068 }
7069
7070 if (arg1 == arg2) {
7071#ifdef DEBUG_EXPR
7072 xmlGenericError(xmlGenericErrorContext,
7073 "Equal: by pointer\n");
7074#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00007075 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007076 return(1);
7077 }
7078
7079 /*
7080 *If either argument is a nodeset, it's a 'special case'
7081 */
7082 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7083 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7084 /*
7085 *Hack it to assure arg1 is the nodeset
7086 */
7087 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7088 argtmp = arg2;
7089 arg2 = arg1;
7090 arg1 = argtmp;
7091 }
7092 switch (arg2->type) {
7093 case XPATH_UNDEFINED:
7094#ifdef DEBUG_EXPR
7095 xmlGenericError(xmlGenericErrorContext,
7096 "Equal: undefined\n");
7097#endif
7098 break;
7099 case XPATH_NODESET:
7100 case XPATH_XSLT_TREE:
7101 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7102 break;
7103 case XPATH_BOOLEAN:
7104 if ((arg1->nodesetval == NULL) ||
7105 (arg1->nodesetval->nodeNr == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007106 else
William M. Brack0c022ad2002-07-12 00:56:01 +00007107 ret = 1;
7108 ret = (ret == arg2->boolval);
7109 break;
7110 case XPATH_NUMBER:
7111 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7112 break;
7113 case XPATH_STRING:
7114 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7115 break;
7116 case XPATH_USERS:
7117 case XPATH_POINT:
7118 case XPATH_RANGE:
7119 case XPATH_LOCATIONSET:
7120 TODO
7121 break;
7122 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007123 xmlXPathReleaseObject(ctxt->context, arg1);
7124 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007125 return(ret);
7126 }
7127
7128 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7129}
7130
7131/**
7132 * xmlXPathNotEqualValues:
7133 * @ctxt: the XPath Parser context
7134 *
7135 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7136 *
7137 * Returns 0 or 1 depending on the results of the test.
7138 */
7139int
7140xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7141 xmlXPathObjectPtr arg1, arg2, argtmp;
7142 int ret = 0;
7143
Daniel Veillard6128c012004-11-08 17:16:15 +00007144 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007145 arg2 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007146 arg1 = valuePop(ctxt);
7147 if ((arg1 == NULL) || (arg2 == NULL)) {
7148 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007149 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007150 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007151 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007152 XP_ERROR0(XPATH_INVALID_OPERAND);
7153 }
7154
7155 if (arg1 == arg2) {
7156#ifdef DEBUG_EXPR
7157 xmlGenericError(xmlGenericErrorContext,
7158 "NotEqual: by pointer\n");
7159#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007160 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007161 return(0);
7162 }
7163
7164 /*
7165 *If either argument is a nodeset, it's a 'special case'
7166 */
7167 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7168 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7169 /*
7170 *Hack it to assure arg1 is the nodeset
7171 */
7172 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7173 argtmp = arg2;
7174 arg2 = arg1;
7175 arg1 = argtmp;
7176 }
7177 switch (arg2->type) {
7178 case XPATH_UNDEFINED:
7179#ifdef DEBUG_EXPR
7180 xmlGenericError(xmlGenericErrorContext,
7181 "NotEqual: undefined\n");
7182#endif
7183 break;
7184 case XPATH_NODESET:
7185 case XPATH_XSLT_TREE:
7186 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7187 break;
7188 case XPATH_BOOLEAN:
7189 if ((arg1->nodesetval == NULL) ||
7190 (arg1->nodesetval->nodeNr == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007191 else
William M. Brack0c022ad2002-07-12 00:56:01 +00007192 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00007193 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00007194 break;
7195 case XPATH_NUMBER:
7196 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7197 break;
7198 case XPATH_STRING:
7199 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7200 break;
7201 case XPATH_USERS:
7202 case XPATH_POINT:
7203 case XPATH_RANGE:
7204 case XPATH_LOCATIONSET:
7205 TODO
7206 break;
7207 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007208 xmlXPathReleaseObject(ctxt->context, arg1);
7209 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007210 return(ret);
7211 }
7212
7213 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7214}
Owen Taylor3473f882001-02-23 17:55:21 +00007215
7216/**
7217 * xmlXPathCompareValues:
7218 * @ctxt: the XPath Parser context
7219 * @inf: less than (1) or greater than (0)
7220 * @strict: is the comparison strict
7221 *
Daniel Veillard45490ae2008-07-29 09:13:19 +00007222 * Implement the compare operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007223 * @arg1 < @arg2 (1, 1, ...
7224 * @arg1 <= @arg2 (1, 0, ...
7225 * @arg1 > @arg2 (0, 1, ...
7226 * @arg1 >= @arg2 (0, 0, ...
7227 *
7228 * When neither object to be compared is a node-set and the operator is
7229 * <=, <, >=, >, then the objects are compared by converted both objects
7230 * to numbers and comparing the numbers according to IEEE 754. The <
7231 * comparison will be true if and only if the first number is less than the
7232 * second number. The <= comparison will be true if and only if the first
7233 * number is less than or equal to the second number. The > comparison
7234 * will be true if and only if the first number is greater than the second
7235 * number. The >= comparison will be true if and only if the first number
7236 * is greater than or equal to the second number.
7237 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007238 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00007239 */
7240int
7241xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007242 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007243 xmlXPathObjectPtr arg1, arg2;
7244
Daniel Veillard6128c012004-11-08 17:16:15 +00007245 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007246 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007247 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007248 if ((arg1 == NULL) || (arg2 == NULL)) {
7249 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007250 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007251 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007252 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007253 XP_ERROR0(XPATH_INVALID_OPERAND);
7254 }
7255
William M. Brack0c022ad2002-07-12 00:56:01 +00007256 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7257 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
William M. Brackd6e347e2005-04-15 01:34:41 +00007258 /*
7259 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7260 * are not freed from within this routine; they will be freed from the
7261 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7262 */
William M. Brack0c022ad2002-07-12 00:56:01 +00007263 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7264 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007265 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007266 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00007267 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007268 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7269 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007270 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007271 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7272 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00007273 }
7274 }
7275 return(ret);
7276 }
7277
7278 if (arg1->type != XPATH_NUMBER) {
7279 valuePush(ctxt, arg1);
7280 xmlXPathNumberFunction(ctxt, 1);
7281 arg1 = valuePop(ctxt);
7282 }
7283 if (arg1->type != XPATH_NUMBER) {
7284 xmlXPathFreeObject(arg1);
7285 xmlXPathFreeObject(arg2);
7286 XP_ERROR0(XPATH_INVALID_OPERAND);
7287 }
7288 if (arg2->type != XPATH_NUMBER) {
7289 valuePush(ctxt, arg2);
7290 xmlXPathNumberFunction(ctxt, 1);
7291 arg2 = valuePop(ctxt);
7292 }
7293 if (arg2->type != XPATH_NUMBER) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007294 xmlXPathReleaseObject(ctxt->context, arg1);
7295 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007296 XP_ERROR0(XPATH_INVALID_OPERAND);
7297 }
7298 /*
7299 * Add tests for infinity and nan
7300 * => feedback on 3.4 for Inf and NaN
7301 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007302 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00007303 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007304 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007305 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007306 arg1i=xmlXPathIsInf(arg1->floatval);
7307 arg2i=xmlXPathIsInf(arg2->floatval);
7308 if (inf && strict) {
7309 if ((arg1i == -1 && arg2i != -1) ||
7310 (arg2i == 1 && arg1i != 1)) {
7311 ret = 1;
7312 } else if (arg1i == 0 && arg2i == 0) {
7313 ret = (arg1->floatval < arg2->floatval);
7314 } else {
7315 ret = 0;
7316 }
7317 }
7318 else if (inf && !strict) {
7319 if (arg1i == -1 || arg2i == 1) {
7320 ret = 1;
7321 } else if (arg1i == 0 && arg2i == 0) {
7322 ret = (arg1->floatval <= arg2->floatval);
7323 } else {
7324 ret = 0;
7325 }
7326 }
7327 else if (!inf && strict) {
7328 if ((arg1i == 1 && arg2i != 1) ||
7329 (arg2i == -1 && arg1i != -1)) {
7330 ret = 1;
7331 } else if (arg1i == 0 && arg2i == 0) {
7332 ret = (arg1->floatval > arg2->floatval);
7333 } else {
7334 ret = 0;
7335 }
7336 }
7337 else if (!inf && !strict) {
7338 if (arg1i == 1 || arg2i == -1) {
7339 ret = 1;
7340 } else if (arg1i == 0 && arg2i == 0) {
7341 ret = (arg1->floatval >= arg2->floatval);
7342 } else {
7343 ret = 0;
7344 }
7345 }
Daniel Veillard21458c82002-03-27 16:12:22 +00007346 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007347 xmlXPathReleaseObject(ctxt->context, arg1);
7348 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007349 return(ret);
7350}
7351
7352/**
7353 * xmlXPathValueFlipSign:
7354 * @ctxt: the XPath Parser context
7355 *
7356 * Implement the unary - operation on an XPath object
7357 * The numeric operators convert their operands to numbers as if
7358 * by calling the number function.
7359 */
7360void
7361xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007362 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007363 CAST_TO_NUMBER;
7364 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007365 if (xmlXPathIsNaN(ctxt->value->floatval))
7366 ctxt->value->floatval=xmlXPathNAN;
7367 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7368 ctxt->value->floatval=xmlXPathNINF;
7369 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7370 ctxt->value->floatval=xmlXPathPINF;
7371 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007372 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7373 ctxt->value->floatval = xmlXPathNZERO;
7374 else
7375 ctxt->value->floatval = 0;
7376 }
7377 else
7378 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00007379}
7380
7381/**
7382 * xmlXPathAddValues:
7383 * @ctxt: the XPath Parser context
7384 *
7385 * Implement the add operation on XPath objects:
7386 * The numeric operators convert their operands to numbers as if
7387 * by calling the number function.
7388 */
7389void
7390xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7391 xmlXPathObjectPtr arg;
7392 double val;
7393
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007394 arg = valuePop(ctxt);
7395 if (arg == NULL)
7396 XP_ERROR(XPATH_INVALID_OPERAND);
7397 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007398 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007399 CAST_TO_NUMBER;
7400 CHECK_TYPE(XPATH_NUMBER);
7401 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00007402}
7403
7404/**
7405 * xmlXPathSubValues:
7406 * @ctxt: the XPath Parser context
7407 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007408 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007409 * The numeric operators convert their operands to numbers as if
7410 * by calling the number function.
7411 */
7412void
7413xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7414 xmlXPathObjectPtr arg;
7415 double val;
7416
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007417 arg = valuePop(ctxt);
7418 if (arg == NULL)
7419 XP_ERROR(XPATH_INVALID_OPERAND);
7420 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007421 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007422 CAST_TO_NUMBER;
7423 CHECK_TYPE(XPATH_NUMBER);
7424 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007425}
7426
7427/**
7428 * xmlXPathMultValues:
7429 * @ctxt: the XPath Parser context
7430 *
7431 * Implement the multiply operation on XPath objects:
7432 * The numeric operators convert their operands to numbers as if
7433 * by calling the number function.
7434 */
7435void
7436xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7437 xmlXPathObjectPtr arg;
7438 double val;
7439
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007440 arg = valuePop(ctxt);
7441 if (arg == NULL)
7442 XP_ERROR(XPATH_INVALID_OPERAND);
7443 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007444 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007445 CAST_TO_NUMBER;
7446 CHECK_TYPE(XPATH_NUMBER);
7447 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007448}
7449
7450/**
7451 * xmlXPathDivValues:
7452 * @ctxt: the XPath Parser context
7453 *
7454 * Implement the div operation on XPath objects @arg1 / @arg2:
7455 * The numeric operators convert their operands to numbers as if
7456 * by calling the number function.
7457 */
7458void
7459xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7460 xmlXPathObjectPtr arg;
7461 double val;
7462
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007463 arg = valuePop(ctxt);
7464 if (arg == NULL)
7465 XP_ERROR(XPATH_INVALID_OPERAND);
7466 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007467 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007468 CAST_TO_NUMBER;
7469 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007470 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7471 ctxt->value->floatval = xmlXPathNAN;
7472 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007473 if (ctxt->value->floatval == 0)
7474 ctxt->value->floatval = xmlXPathNAN;
7475 else if (ctxt->value->floatval > 0)
7476 ctxt->value->floatval = xmlXPathNINF;
7477 else if (ctxt->value->floatval < 0)
7478 ctxt->value->floatval = xmlXPathPINF;
7479 }
7480 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007481 if (ctxt->value->floatval == 0)
7482 ctxt->value->floatval = xmlXPathNAN;
7483 else if (ctxt->value->floatval > 0)
7484 ctxt->value->floatval = xmlXPathPINF;
7485 else if (ctxt->value->floatval < 0)
7486 ctxt->value->floatval = xmlXPathNINF;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007487 } else
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007488 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007489}
7490
7491/**
7492 * xmlXPathModValues:
7493 * @ctxt: the XPath Parser context
7494 *
7495 * Implement the mod operation on XPath objects: @arg1 / @arg2
7496 * The numeric operators convert their operands to numbers as if
7497 * by calling the number function.
7498 */
7499void
7500xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7501 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00007502 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00007503
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007504 arg = valuePop(ctxt);
7505 if (arg == NULL)
7506 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007507 arg2 = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007508 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007509 CAST_TO_NUMBER;
7510 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007511 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00007512 if (arg2 == 0)
7513 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007514 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00007515 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007516 }
Owen Taylor3473f882001-02-23 17:55:21 +00007517}
7518
7519/************************************************************************
7520 * *
7521 * The traversal functions *
7522 * *
7523 ************************************************************************/
7524
Owen Taylor3473f882001-02-23 17:55:21 +00007525/*
7526 * A traversal function enumerates nodes along an axis.
7527 * Initially it must be called with NULL, and it indicates
7528 * termination on the axis by returning NULL.
7529 */
7530typedef xmlNodePtr (*xmlXPathTraversalFunction)
7531 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7532
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007533/*
7534 * xmlXPathTraversalFunctionExt:
7535 * A traversal function enumerates nodes along an axis.
7536 * Initially it must be called with NULL, and it indicates
7537 * termination on the axis by returning NULL.
7538 * The context node of the traversal is specified via @contextNode.
7539 */
7540typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7541 (xmlNodePtr cur, xmlNodePtr contextNode);
7542
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00007543/*
7544 * xmlXPathNodeSetMergeFunction:
7545 * Used for merging node sets in xmlXPathCollectAndTest().
7546 */
7547typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7548 (xmlNodeSetPtr, xmlNodeSetPtr, int);
7549
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007550
Owen Taylor3473f882001-02-23 17:55:21 +00007551/**
7552 * xmlXPathNextSelf:
7553 * @ctxt: the XPath Parser context
7554 * @cur: the current node in the traversal
7555 *
7556 * Traversal function for the "self" direction
7557 * The self axis contains just the context node itself
7558 *
7559 * Returns the next element following that axis
7560 */
7561xmlNodePtr
7562xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007563 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007564 if (cur == NULL)
7565 return(ctxt->context->node);
7566 return(NULL);
7567}
7568
7569/**
7570 * xmlXPathNextChild:
7571 * @ctxt: the XPath Parser context
7572 * @cur: the current node in the traversal
7573 *
7574 * Traversal function for the "child" direction
7575 * The child axis contains the children of the context node in document order.
7576 *
7577 * Returns the next element following that axis
7578 */
7579xmlNodePtr
7580xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007581 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007582 if (cur == NULL) {
7583 if (ctxt->context->node == NULL) return(NULL);
7584 switch (ctxt->context->node->type) {
7585 case XML_ELEMENT_NODE:
7586 case XML_TEXT_NODE:
7587 case XML_CDATA_SECTION_NODE:
7588 case XML_ENTITY_REF_NODE:
7589 case XML_ENTITY_NODE:
7590 case XML_PI_NODE:
7591 case XML_COMMENT_NODE:
7592 case XML_NOTATION_NODE:
7593 case XML_DTD_NODE:
7594 return(ctxt->context->node->children);
7595 case XML_DOCUMENT_NODE:
7596 case XML_DOCUMENT_TYPE_NODE:
7597 case XML_DOCUMENT_FRAG_NODE:
7598 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007599#ifdef LIBXML_DOCB_ENABLED
7600 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007601#endif
7602 return(((xmlDocPtr) ctxt->context->node)->children);
7603 case XML_ELEMENT_DECL:
7604 case XML_ATTRIBUTE_DECL:
7605 case XML_ENTITY_DECL:
7606 case XML_ATTRIBUTE_NODE:
7607 case XML_NAMESPACE_DECL:
7608 case XML_XINCLUDE_START:
7609 case XML_XINCLUDE_END:
7610 return(NULL);
7611 }
7612 return(NULL);
7613 }
7614 if ((cur->type == XML_DOCUMENT_NODE) ||
7615 (cur->type == XML_HTML_DOCUMENT_NODE))
7616 return(NULL);
7617 return(cur->next);
7618}
7619
7620/**
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00007621 * xmlXPathNextChildElement:
7622 * @ctxt: the XPath Parser context
7623 * @cur: the current node in the traversal
7624 *
7625 * Traversal function for the "child" direction and nodes of type element.
7626 * The child axis contains the children of the context node in document order.
7627 *
7628 * Returns the next element following that axis
7629 */
7630static xmlNodePtr
7631xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7632 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7633 if (cur == NULL) {
7634 cur = ctxt->context->node;
7635 if (cur == NULL) return(NULL);
7636 /*
7637 * Get the first element child.
7638 */
7639 switch (cur->type) {
7640 case XML_ELEMENT_NODE:
7641 case XML_DOCUMENT_FRAG_NODE:
7642 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7643 case XML_ENTITY_NODE:
7644 cur = cur->children;
7645 if (cur != NULL) {
7646 if (cur->type == XML_ELEMENT_NODE)
7647 return(cur);
7648 do {
7649 cur = cur->next;
7650 } while ((cur != NULL) &&
7651 (cur->type != XML_ELEMENT_NODE));
7652 return(cur);
7653 }
7654 return(NULL);
7655 case XML_DOCUMENT_NODE:
7656 case XML_HTML_DOCUMENT_NODE:
7657#ifdef LIBXML_DOCB_ENABLED
7658 case XML_DOCB_DOCUMENT_NODE:
7659#endif
7660 return(xmlDocGetRootElement((xmlDocPtr) cur));
7661 default:
7662 return(NULL);
7663 }
7664 return(NULL);
7665 }
7666 /*
7667 * Get the next sibling element node.
7668 */
7669 switch (cur->type) {
7670 case XML_ELEMENT_NODE:
7671 case XML_TEXT_NODE:
7672 case XML_ENTITY_REF_NODE:
7673 case XML_ENTITY_NODE:
7674 case XML_CDATA_SECTION_NODE:
7675 case XML_PI_NODE:
7676 case XML_COMMENT_NODE:
7677 case XML_XINCLUDE_END:
7678 break;
7679 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7680 default:
7681 return(NULL);
7682 }
7683 if (cur->next != NULL) {
7684 if (cur->next->type == XML_ELEMENT_NODE)
7685 return(cur->next);
7686 cur = cur->next;
7687 do {
7688 cur = cur->next;
7689 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7690 return(cur);
7691 }
7692 return(NULL);
7693}
7694
7695/**
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007696 * xmlXPathNextDescendantOrSelfElemParent:
7697 * @ctxt: the XPath Parser context
7698 * @cur: the current node in the traversal
7699 *
7700 * Traversal function for the "descendant-or-self" axis.
7701 * Additionally it returns only nodes which can be parents of
7702 * element nodes.
7703 *
7704 *
7705 * Returns the next element following that axis
7706 */
7707static xmlNodePtr
7708xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7709 xmlNodePtr contextNode)
7710{
7711 if (cur == NULL) {
7712 if (contextNode == NULL)
7713 return(NULL);
7714 switch (contextNode->type) {
7715 case XML_ELEMENT_NODE:
7716 case XML_XINCLUDE_START:
7717 case XML_DOCUMENT_FRAG_NODE:
7718 case XML_DOCUMENT_NODE:
7719#ifdef LIBXML_DOCB_ENABLED
7720 case XML_DOCB_DOCUMENT_NODE:
7721#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00007722 case XML_HTML_DOCUMENT_NODE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007723 return(contextNode);
7724 default:
Daniel Veillard45490ae2008-07-29 09:13:19 +00007725 return(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007726 }
7727 return(NULL);
7728 } else {
7729 xmlNodePtr start = cur;
7730
7731 while (cur != NULL) {
7732 switch (cur->type) {
7733 case XML_ELEMENT_NODE:
7734 /* TODO: OK to have XInclude here? */
7735 case XML_XINCLUDE_START:
Daniel Veillard45490ae2008-07-29 09:13:19 +00007736 case XML_DOCUMENT_FRAG_NODE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007737 if (cur != start)
7738 return(cur);
7739 if (cur->children != NULL) {
7740 cur = cur->children;
7741 continue;
7742 }
7743 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007744 /* Not sure if we need those here. */
7745 case XML_DOCUMENT_NODE:
Daniel Veillard17970a72006-10-26 08:55:47 +00007746#ifdef LIBXML_DOCB_ENABLED
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007747 case XML_DOCB_DOCUMENT_NODE:
7748#endif
7749 case XML_HTML_DOCUMENT_NODE:
7750 if (cur != start)
7751 return(cur);
7752 return(xmlDocGetRootElement((xmlDocPtr) cur));
7753 default:
7754 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007755 }
7756
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007757next_sibling:
7758 if ((cur == NULL) || (cur == contextNode))
Daniel Veillard45490ae2008-07-29 09:13:19 +00007759 return(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007760 if (cur->next != NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00007761 cur = cur->next;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007762 } else {
7763 cur = cur->parent;
7764 goto next_sibling;
7765 }
7766 }
7767 }
7768 return(NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007769}
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007770
7771/**
Owen Taylor3473f882001-02-23 17:55:21 +00007772 * xmlXPathNextDescendant:
7773 * @ctxt: the XPath Parser context
7774 * @cur: the current node in the traversal
7775 *
7776 * Traversal function for the "descendant" direction
7777 * the descendant axis contains the descendants of the context node in document
7778 * order; a descendant is a child or a child of a child and so on.
7779 *
7780 * Returns the next element following that axis
7781 */
7782xmlNodePtr
7783xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007784 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007785 if (cur == NULL) {
7786 if (ctxt->context->node == NULL)
7787 return(NULL);
7788 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7789 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7790 return(NULL);
7791
7792 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7793 return(ctxt->context->doc->children);
7794 return(ctxt->context->node->children);
7795 }
7796
Daniel Veillard3e62adb2012-08-09 14:24:02 +08007797 if (cur->type == XML_NAMESPACE_DECL)
7798 return(NULL);
Daniel Veillard567e1b42001-08-01 15:53:47 +00007799 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007800 /*
7801 * Do not descend on entities declarations
7802 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00007803 if (cur->children->type != XML_ENTITY_DECL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007804 cur = cur->children;
7805 /*
7806 * Skip DTDs
7807 */
7808 if (cur->type != XML_DTD_NODE)
7809 return(cur);
7810 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00007811 }
7812
7813 if (cur == ctxt->context->node) return(NULL);
7814
Daniel Veillard68e9e742002-11-16 15:35:11 +00007815 while (cur->next != NULL) {
7816 cur = cur->next;
7817 if ((cur->type != XML_ENTITY_DECL) &&
7818 (cur->type != XML_DTD_NODE))
7819 return(cur);
7820 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00007821
Owen Taylor3473f882001-02-23 17:55:21 +00007822 do {
7823 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00007824 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00007825 if (cur == ctxt->context->node) return(NULL);
7826 if (cur->next != NULL) {
7827 cur = cur->next;
7828 return(cur);
7829 }
7830 } while (cur != NULL);
7831 return(cur);
7832}
7833
7834/**
7835 * xmlXPathNextDescendantOrSelf:
7836 * @ctxt: the XPath Parser context
7837 * @cur: the current node in the traversal
7838 *
7839 * Traversal function for the "descendant-or-self" direction
7840 * the descendant-or-self axis contains the context node and the descendants
7841 * of the context node in document order; thus the context node is the first
7842 * node on the axis, and the first child of the context node is the second node
7843 * on the axis
7844 *
7845 * Returns the next element following that axis
7846 */
7847xmlNodePtr
7848xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007849 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007850 if (cur == NULL) {
7851 if (ctxt->context->node == NULL)
7852 return(NULL);
7853 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7854 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7855 return(NULL);
7856 return(ctxt->context->node);
7857 }
7858
7859 return(xmlXPathNextDescendant(ctxt, cur));
7860}
7861
7862/**
7863 * xmlXPathNextParent:
7864 * @ctxt: the XPath Parser context
7865 * @cur: the current node in the traversal
7866 *
7867 * Traversal function for the "parent" direction
7868 * The parent axis contains the parent of the context node, if there is one.
7869 *
7870 * Returns the next element following that axis
7871 */
7872xmlNodePtr
7873xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007874 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007875 /*
7876 * the parent of an attribute or namespace node is the element
7877 * to which the attribute or namespace node is attached
7878 * Namespace handling !!!
7879 */
7880 if (cur == NULL) {
7881 if (ctxt->context->node == NULL) return(NULL);
7882 switch (ctxt->context->node->type) {
7883 case XML_ELEMENT_NODE:
7884 case XML_TEXT_NODE:
7885 case XML_CDATA_SECTION_NODE:
7886 case XML_ENTITY_REF_NODE:
7887 case XML_ENTITY_NODE:
7888 case XML_PI_NODE:
7889 case XML_COMMENT_NODE:
7890 case XML_NOTATION_NODE:
7891 case XML_DTD_NODE:
7892 case XML_ELEMENT_DECL:
7893 case XML_ATTRIBUTE_DECL:
7894 case XML_XINCLUDE_START:
7895 case XML_XINCLUDE_END:
7896 case XML_ENTITY_DECL:
7897 if (ctxt->context->node->parent == NULL)
7898 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007899 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007900 ((ctxt->context->node->parent->name[0] == ' ') ||
7901 (xmlStrEqual(ctxt->context->node->parent->name,
7902 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007903 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007904 return(ctxt->context->node->parent);
7905 case XML_ATTRIBUTE_NODE: {
7906 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7907
7908 return(att->parent);
7909 }
7910 case XML_DOCUMENT_NODE:
7911 case XML_DOCUMENT_TYPE_NODE:
7912 case XML_DOCUMENT_FRAG_NODE:
7913 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007914#ifdef LIBXML_DOCB_ENABLED
7915 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007916#endif
7917 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007918 case XML_NAMESPACE_DECL: {
7919 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007920
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007921 if ((ns->next != NULL) &&
7922 (ns->next->type != XML_NAMESPACE_DECL))
7923 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00007924 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007925 }
Owen Taylor3473f882001-02-23 17:55:21 +00007926 }
7927 }
7928 return(NULL);
7929}
7930
7931/**
7932 * xmlXPathNextAncestor:
7933 * @ctxt: the XPath Parser context
7934 * @cur: the current node in the traversal
7935 *
7936 * Traversal function for the "ancestor" direction
7937 * the ancestor axis contains the ancestors of the context node; the ancestors
7938 * of the context node consist of the parent of context node and the parent's
7939 * parent and so on; the nodes are ordered in reverse document order; thus the
7940 * parent is the first node on the axis, and the parent's parent is the second
7941 * node on the axis
7942 *
7943 * Returns the next element following that axis
7944 */
7945xmlNodePtr
7946xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007947 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007948 /*
7949 * the parent of an attribute or namespace node is the element
7950 * to which the attribute or namespace node is attached
7951 * !!!!!!!!!!!!!
7952 */
7953 if (cur == NULL) {
7954 if (ctxt->context->node == NULL) return(NULL);
7955 switch (ctxt->context->node->type) {
7956 case XML_ELEMENT_NODE:
7957 case XML_TEXT_NODE:
7958 case XML_CDATA_SECTION_NODE:
7959 case XML_ENTITY_REF_NODE:
7960 case XML_ENTITY_NODE:
7961 case XML_PI_NODE:
7962 case XML_COMMENT_NODE:
7963 case XML_DTD_NODE:
7964 case XML_ELEMENT_DECL:
7965 case XML_ATTRIBUTE_DECL:
7966 case XML_ENTITY_DECL:
7967 case XML_NOTATION_NODE:
7968 case XML_XINCLUDE_START:
7969 case XML_XINCLUDE_END:
7970 if (ctxt->context->node->parent == NULL)
7971 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007972 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007973 ((ctxt->context->node->parent->name[0] == ' ') ||
7974 (xmlStrEqual(ctxt->context->node->parent->name,
7975 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007976 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007977 return(ctxt->context->node->parent);
7978 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007979 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00007980
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007981 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00007982 }
7983 case XML_DOCUMENT_NODE:
7984 case XML_DOCUMENT_TYPE_NODE:
7985 case XML_DOCUMENT_FRAG_NODE:
7986 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007987#ifdef LIBXML_DOCB_ENABLED
7988 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007989#endif
7990 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007991 case XML_NAMESPACE_DECL: {
7992 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007993
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007994 if ((ns->next != NULL) &&
7995 (ns->next->type != XML_NAMESPACE_DECL))
7996 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00007997 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00007998 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007999 }
Owen Taylor3473f882001-02-23 17:55:21 +00008000 }
8001 return(NULL);
8002 }
8003 if (cur == ctxt->context->doc->children)
8004 return((xmlNodePtr) ctxt->context->doc);
8005 if (cur == (xmlNodePtr) ctxt->context->doc)
8006 return(NULL);
8007 switch (cur->type) {
8008 case XML_ELEMENT_NODE:
8009 case XML_TEXT_NODE:
8010 case XML_CDATA_SECTION_NODE:
8011 case XML_ENTITY_REF_NODE:
8012 case XML_ENTITY_NODE:
8013 case XML_PI_NODE:
8014 case XML_COMMENT_NODE:
8015 case XML_NOTATION_NODE:
8016 case XML_DTD_NODE:
8017 case XML_ELEMENT_DECL:
8018 case XML_ATTRIBUTE_DECL:
8019 case XML_ENTITY_DECL:
8020 case XML_XINCLUDE_START:
8021 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008022 if (cur->parent == NULL)
8023 return(NULL);
8024 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00008025 ((cur->parent->name[0] == ' ') ||
8026 (xmlStrEqual(cur->parent->name,
8027 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008028 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008029 return(cur->parent);
8030 case XML_ATTRIBUTE_NODE: {
8031 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
8032
8033 return(att->parent);
8034 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008035 case XML_NAMESPACE_DECL: {
8036 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008037
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008038 if ((ns->next != NULL) &&
8039 (ns->next->type != XML_NAMESPACE_DECL))
8040 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00008041 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008042 return(NULL);
8043 }
Owen Taylor3473f882001-02-23 17:55:21 +00008044 case XML_DOCUMENT_NODE:
8045 case XML_DOCUMENT_TYPE_NODE:
8046 case XML_DOCUMENT_FRAG_NODE:
8047 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00008048#ifdef LIBXML_DOCB_ENABLED
8049 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00008050#endif
8051 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008052 }
8053 return(NULL);
8054}
8055
8056/**
8057 * xmlXPathNextAncestorOrSelf:
8058 * @ctxt: the XPath Parser context
8059 * @cur: the current node in the traversal
8060 *
8061 * Traversal function for the "ancestor-or-self" direction
8062 * he ancestor-or-self axis contains the context node and ancestors of
8063 * the context node in reverse document order; thus the context node is
8064 * the first node on the axis, and the context node's parent the second;
8065 * parent here is defined the same as with the parent axis.
8066 *
8067 * Returns the next element following that axis
8068 */
8069xmlNodePtr
8070xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008071 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008072 if (cur == NULL)
8073 return(ctxt->context->node);
8074 return(xmlXPathNextAncestor(ctxt, cur));
8075}
8076
8077/**
8078 * xmlXPathNextFollowingSibling:
8079 * @ctxt: the XPath Parser context
8080 * @cur: the current node in the traversal
8081 *
8082 * Traversal function for the "following-sibling" direction
8083 * The following-sibling axis contains the following siblings of the context
8084 * node in document order.
8085 *
8086 * Returns the next element following that axis
8087 */
8088xmlNodePtr
8089xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008090 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008091 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8092 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8093 return(NULL);
8094 if (cur == (xmlNodePtr) ctxt->context->doc)
8095 return(NULL);
8096 if (cur == NULL)
8097 return(ctxt->context->node->next);
8098 return(cur->next);
8099}
8100
8101/**
8102 * xmlXPathNextPrecedingSibling:
8103 * @ctxt: the XPath Parser context
8104 * @cur: the current node in the traversal
8105 *
8106 * Traversal function for the "preceding-sibling" direction
8107 * The preceding-sibling axis contains the preceding siblings of the context
8108 * node in reverse document order; the first preceding sibling is first on the
8109 * axis; the sibling preceding that node is the second on the axis and so on.
8110 *
8111 * Returns the next element following that axis
8112 */
8113xmlNodePtr
8114xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008115 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008116 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8117 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8118 return(NULL);
8119 if (cur == (xmlNodePtr) ctxt->context->doc)
8120 return(NULL);
8121 if (cur == NULL)
8122 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008123 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8124 cur = cur->prev;
8125 if (cur == NULL)
8126 return(ctxt->context->node->prev);
8127 }
Owen Taylor3473f882001-02-23 17:55:21 +00008128 return(cur->prev);
8129}
8130
8131/**
8132 * xmlXPathNextFollowing:
8133 * @ctxt: the XPath Parser context
8134 * @cur: the current node in the traversal
8135 *
8136 * Traversal function for the "following" direction
8137 * The following axis contains all nodes in the same document as the context
8138 * node that are after the context node in document order, excluding any
8139 * descendants and excluding attribute nodes and namespace nodes; the nodes
8140 * are ordered in document order
8141 *
8142 * Returns the next element following that axis
8143 */
8144xmlNodePtr
8145xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008146 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008147 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
8148 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8149 return(cur->children);
8150
8151 if (cur == NULL) {
8152 cur = ctxt->context->node;
8153 if (cur->type == XML_NAMESPACE_DECL)
Daniel Veillard91d19752010-10-15 14:30:52 +02008154 return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008155 if (cur->type == XML_ATTRIBUTE_NODE)
8156 cur = cur->parent;
Daniel Veillard91d19752010-10-15 14:30:52 +02008157 }
Owen Taylor3473f882001-02-23 17:55:21 +00008158 if (cur == NULL) return(NULL) ; /* ERROR */
8159 if (cur->next != NULL) return(cur->next) ;
8160 do {
8161 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00008162 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00008163 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8164 if (cur->next != NULL) return(cur->next);
8165 } while (cur != NULL);
8166 return(cur);
8167}
8168
8169/*
8170 * xmlXPathIsAncestor:
8171 * @ancestor: the ancestor node
8172 * @node: the current node
8173 *
8174 * Check that @ancestor is a @node's ancestor
8175 *
8176 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8177 */
8178static int
8179xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8180 if ((ancestor == NULL) || (node == NULL)) return(0);
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008181 if (node->type == XML_NAMESPACE_DECL)
8182 return(0);
8183 if (ancestor->type == XML_NAMESPACE_DECL)
8184 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00008185 /* nodes need to be in the same document */
8186 if (ancestor->doc != node->doc) return(0);
8187 /* avoid searching if ancestor or node is the root node */
8188 if (ancestor == (xmlNodePtr) node->doc) return(1);
8189 if (node == (xmlNodePtr) ancestor->doc) return(0);
8190 while (node->parent != NULL) {
8191 if (node->parent == ancestor)
8192 return(1);
8193 node = node->parent;
8194 }
8195 return(0);
8196}
8197
8198/**
8199 * xmlXPathNextPreceding:
8200 * @ctxt: the XPath Parser context
8201 * @cur: the current node in the traversal
8202 *
8203 * Traversal function for the "preceding" direction
8204 * the preceding axis contains all nodes in the same document as the context
8205 * node that are before the context node in document order, excluding any
8206 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8207 * ordered in reverse document order
8208 *
8209 * Returns the next element following that axis
8210 */
8211xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00008212xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8213{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008214 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008215 if (cur == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008216 cur = ctxt->context->node;
Daniel Veillardea90b892010-10-22 15:50:50 +02008217 if (cur->type == XML_NAMESPACE_DECL)
8218 return(NULL);
8219 if (cur->type == XML_ATTRIBUTE_NODE)
8220 return(cur->parent);
8221 }
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008222 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
Daniel Veillardf06307e2001-07-03 10:35:50 +00008223 return (NULL);
8224 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8225 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00008226 do {
8227 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008228 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8229 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008230 }
8231
8232 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008233 if (cur == NULL)
8234 return (NULL);
8235 if (cur == ctxt->context->doc->children)
8236 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008237 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00008238 return (cur);
8239}
8240
8241/**
8242 * xmlXPathNextPrecedingInternal:
8243 * @ctxt: the XPath Parser context
8244 * @cur: the current node in the traversal
8245 *
8246 * Traversal function for the "preceding" direction
8247 * the preceding axis contains all nodes in the same document as the context
8248 * node that are before the context node in document order, excluding any
8249 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8250 * ordered in reverse document order
Daniel Veillard45490ae2008-07-29 09:13:19 +00008251 * This is a faster implementation but internal only since it requires a
Daniel Veillardf06307e2001-07-03 10:35:50 +00008252 * state kept in the parser context: ctxt->ancestor.
8253 *
8254 * Returns the next element following that axis
8255 */
8256static xmlNodePtr
8257xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8258 xmlNodePtr cur)
8259{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008260 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008261 if (cur == NULL) {
8262 cur = ctxt->context->node;
8263 if (cur == NULL)
8264 return (NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008265 if (cur->type == XML_NAMESPACE_DECL)
8266 return (NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008267 ctxt->ancestor = cur->parent;
8268 }
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008269 if (cur->type == XML_NAMESPACE_DECL)
8270 return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008271 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8272 cur = cur->prev;
8273 while (cur->prev == NULL) {
8274 cur = cur->parent;
8275 if (cur == NULL)
8276 return (NULL);
8277 if (cur == ctxt->context->doc->children)
8278 return (NULL);
8279 if (cur != ctxt->ancestor)
8280 return (cur);
8281 ctxt->ancestor = cur->parent;
8282 }
8283 cur = cur->prev;
8284 while (cur->last != NULL)
8285 cur = cur->last;
8286 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008287}
8288
8289/**
8290 * xmlXPathNextNamespace:
8291 * @ctxt: the XPath Parser context
8292 * @cur: the current attribute in the traversal
8293 *
8294 * Traversal function for the "namespace" direction
8295 * the namespace axis contains the namespace nodes of the context node;
8296 * the order of nodes on this axis is implementation-defined; the axis will
8297 * be empty unless the context node is an element
8298 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008299 * We keep the XML namespace node at the end of the list.
8300 *
Owen Taylor3473f882001-02-23 17:55:21 +00008301 * Returns the next element following that axis
8302 */
8303xmlNodePtr
8304xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008305 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008306 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00008307 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008308 if (ctxt->context->tmpNsList != NULL)
8309 xmlFree(ctxt->context->tmpNsList);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008310 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00008311 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008312 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00008313 if (ctxt->context->tmpNsList != NULL) {
8314 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8315 ctxt->context->tmpNsNr++;
8316 }
8317 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008318 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008319 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00008320 if (ctxt->context->tmpNsNr > 0) {
8321 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8322 } else {
8323 if (ctxt->context->tmpNsList != NULL)
8324 xmlFree(ctxt->context->tmpNsList);
8325 ctxt->context->tmpNsList = NULL;
8326 return(NULL);
8327 }
Owen Taylor3473f882001-02-23 17:55:21 +00008328}
8329
8330/**
8331 * xmlXPathNextAttribute:
8332 * @ctxt: the XPath Parser context
8333 * @cur: the current attribute in the traversal
8334 *
8335 * Traversal function for the "attribute" direction
8336 * TODO: support DTD inherited default attributes
8337 *
8338 * Returns the next element following that axis
8339 */
8340xmlNodePtr
8341xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008342 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00008343 if (ctxt->context->node == NULL)
8344 return(NULL);
8345 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8346 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008347 if (cur == NULL) {
8348 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8349 return(NULL);
8350 return((xmlNodePtr)ctxt->context->node->properties);
8351 }
8352 return((xmlNodePtr)cur->next);
8353}
8354
8355/************************************************************************
8356 * *
8357 * NodeTest Functions *
8358 * *
8359 ************************************************************************/
8360
Owen Taylor3473f882001-02-23 17:55:21 +00008361#define IS_FUNCTION 200
8362
Owen Taylor3473f882001-02-23 17:55:21 +00008363
8364/************************************************************************
8365 * *
8366 * Implicit tree core function library *
8367 * *
8368 ************************************************************************/
8369
8370/**
8371 * xmlXPathRoot:
8372 * @ctxt: the XPath Parser context
8373 *
8374 * Initialize the context to the root of the document
8375 */
8376void
8377xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008378 if ((ctxt == NULL) || (ctxt->context == NULL))
8379 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008380 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008381 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8382 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008383}
8384
8385/************************************************************************
8386 * *
8387 * The explicit core function library *
8388 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8389 * *
8390 ************************************************************************/
8391
8392
8393/**
8394 * xmlXPathLastFunction:
8395 * @ctxt: the XPath Parser context
8396 * @nargs: the number of arguments
8397 *
8398 * Implement the last() XPath function
8399 * number last()
8400 * The last function returns the number of nodes in the context node list.
8401 */
8402void
8403xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8404 CHECK_ARITY(0);
8405 if (ctxt->context->contextSize >= 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008406 valuePush(ctxt,
8407 xmlXPathCacheNewFloat(ctxt->context,
8408 (double) ctxt->context->contextSize));
Owen Taylor3473f882001-02-23 17:55:21 +00008409#ifdef DEBUG_EXPR
8410 xmlGenericError(xmlGenericErrorContext,
8411 "last() : %d\n", ctxt->context->contextSize);
8412#endif
8413 } else {
8414 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8415 }
8416}
8417
8418/**
8419 * xmlXPathPositionFunction:
8420 * @ctxt: the XPath Parser context
8421 * @nargs: the number of arguments
8422 *
8423 * Implement the position() XPath function
8424 * number position()
8425 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008426 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00008427 * will be equal to last().
8428 */
8429void
8430xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8431 CHECK_ARITY(0);
8432 if (ctxt->context->proximityPosition >= 0) {
8433 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008434 xmlXPathCacheNewFloat(ctxt->context,
8435 (double) ctxt->context->proximityPosition));
Owen Taylor3473f882001-02-23 17:55:21 +00008436#ifdef DEBUG_EXPR
8437 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8438 ctxt->context->proximityPosition);
8439#endif
8440 } else {
8441 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8442 }
8443}
8444
8445/**
8446 * xmlXPathCountFunction:
8447 * @ctxt: the XPath Parser context
8448 * @nargs: the number of arguments
8449 *
8450 * Implement the count() XPath function
8451 * number count(node-set)
8452 */
8453void
8454xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8455 xmlXPathObjectPtr cur;
8456
8457 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008458 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008459 ((ctxt->value->type != XPATH_NODESET) &&
8460 (ctxt->value->type != XPATH_XSLT_TREE)))
8461 XP_ERROR(XPATH_INVALID_TYPE);
8462 cur = valuePop(ctxt);
8463
Daniel Veillard911f49a2001-04-07 15:39:35 +00008464 if ((cur == NULL) || (cur->nodesetval == NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008465 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00008466 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008467 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8468 (double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00008469 } else {
8470 if ((cur->nodesetval->nodeNr != 1) ||
8471 (cur->nodesetval->nodeTab == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008472 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00008473 } else {
8474 xmlNodePtr tmp;
8475 int i = 0;
8476
8477 tmp = cur->nodesetval->nodeTab[0];
Daniel Veillard3e62adb2012-08-09 14:24:02 +08008478 if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) {
Daniel Veillardfe703322001-08-14 12:18:09 +00008479 tmp = tmp->children;
8480 while (tmp != NULL) {
8481 tmp = tmp->next;
8482 i++;
8483 }
8484 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008485 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
Daniel Veillardfe703322001-08-14 12:18:09 +00008486 }
8487 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008488 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008489}
8490
8491/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008492 * xmlXPathGetElementsByIds:
8493 * @doc: the document
8494 * @ids: a whitespace separated list of IDs
8495 *
8496 * Selects elements by their unique ID.
8497 *
8498 * Returns a node-set of selected elements.
8499 */
8500static xmlNodeSetPtr
8501xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8502 xmlNodeSetPtr ret;
8503 const xmlChar *cur = ids;
8504 xmlChar *ID;
8505 xmlAttrPtr attr;
8506 xmlNodePtr elem = NULL;
8507
Daniel Veillard7a985a12003-07-06 17:57:42 +00008508 if (ids == NULL) return(NULL);
8509
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008510 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00008511 if (ret == NULL)
8512 return(ret);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008513
William M. Brack76e95df2003-10-18 16:20:14 +00008514 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008515 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008516 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00008517 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008518
8519 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00008520 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00008521 /*
8522 * We used to check the fact that the value passed
8523 * was an NCName, but this generated much troubles for
8524 * me and Aleksey Sanin, people blatantly violated that
8525 * constaint, like Visa3D spec.
8526 * if (xmlValidateNCName(ID, 1) == 0)
8527 */
8528 attr = xmlGetID(doc, ID);
8529 if (attr != NULL) {
8530 if (attr->type == XML_ATTRIBUTE_NODE)
8531 elem = attr->parent;
8532 else if (attr->type == XML_ELEMENT_NODE)
8533 elem = (xmlNodePtr) attr;
8534 else
8535 elem = NULL;
8536 if (elem != NULL)
8537 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00008538 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008539 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00008540 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008541
William M. Brack76e95df2003-10-18 16:20:14 +00008542 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008543 ids = cur;
8544 }
8545 return(ret);
8546}
8547
8548/**
Owen Taylor3473f882001-02-23 17:55:21 +00008549 * xmlXPathIdFunction:
8550 * @ctxt: the XPath Parser context
8551 * @nargs: the number of arguments
8552 *
8553 * Implement the id() XPath function
8554 * node-set id(object)
8555 * The id function selects elements by their unique ID
8556 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8557 * then the result is the union of the result of applying id to the
8558 * string value of each of the nodes in the argument node-set. When the
8559 * argument to id is of any other type, the argument is converted to a
8560 * string as if by a call to the string function; the string is split
8561 * into a whitespace-separated list of tokens (whitespace is any sequence
8562 * of characters matching the production S); the result is a node-set
8563 * containing the elements in the same document as the context node that
8564 * have a unique ID equal to any of the tokens in the list.
8565 */
8566void
8567xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008568 xmlChar *tokens;
8569 xmlNodeSetPtr ret;
8570 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00008571
8572 CHECK_ARITY(1);
8573 obj = valuePop(ctxt);
8574 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00008575 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008576 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00008577 int i;
8578
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008579 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00008580 /*
8581 * FIXME -- in an out-of-memory condition this will behave badly.
8582 * The solution is not clear -- we already popped an item from
8583 * ctxt, so the object is in a corrupt state.
8584 */
Owen Taylor3473f882001-02-23 17:55:21 +00008585
Daniel Veillard911f49a2001-04-07 15:39:35 +00008586 if (obj->nodesetval != NULL) {
8587 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008588 tokens =
8589 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8590 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8591 ret = xmlXPathNodeSetMerge(ret, ns);
8592 xmlXPathFreeNodeSet(ns);
8593 if (tokens != NULL)
8594 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00008595 }
Owen Taylor3473f882001-02-23 17:55:21 +00008596 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008597 xmlXPathReleaseObject(ctxt->context, obj);
8598 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00008599 return;
8600 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008601 obj = xmlXPathCacheConvertString(ctxt->context, obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008602 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008603 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008604 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00008605 return;
8606}
8607
8608/**
8609 * xmlXPathLocalNameFunction:
8610 * @ctxt: the XPath Parser context
8611 * @nargs: the number of arguments
8612 *
8613 * Implement the local-name() XPath function
8614 * string local-name(node-set?)
8615 * The local-name function returns a string containing the local part
8616 * of the name of the node in the argument node-set that is first in
8617 * document order. If the node-set is empty or the first node has no
8618 * name, an empty string is returned. If the argument is omitted it
8619 * defaults to the context node.
8620 */
8621void
8622xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8623 xmlXPathObjectPtr cur;
8624
Daniel Veillarda82b1822004-11-08 16:24:57 +00008625 if (ctxt == NULL) return;
8626
Owen Taylor3473f882001-02-23 17:55:21 +00008627 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008628 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8629 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008630 nargs = 1;
8631 }
8632
8633 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008634 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008635 ((ctxt->value->type != XPATH_NODESET) &&
8636 (ctxt->value->type != XPATH_XSLT_TREE)))
8637 XP_ERROR(XPATH_INVALID_TYPE);
8638 cur = valuePop(ctxt);
8639
Daniel Veillard911f49a2001-04-07 15:39:35 +00008640 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008641 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008642 } else {
8643 int i = 0; /* Should be first in document order !!!!! */
8644 switch (cur->nodesetval->nodeTab[i]->type) {
8645 case XML_ELEMENT_NODE:
8646 case XML_ATTRIBUTE_NODE:
8647 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008648 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008649 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008650 else
8651 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008652 xmlXPathCacheNewString(ctxt->context,
8653 cur->nodesetval->nodeTab[i]->name));
Owen Taylor3473f882001-02-23 17:55:21 +00008654 break;
8655 case XML_NAMESPACE_DECL:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008656 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008657 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8658 break;
8659 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008660 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008661 }
8662 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008663 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008664}
8665
8666/**
8667 * xmlXPathNamespaceURIFunction:
8668 * @ctxt: the XPath Parser context
8669 * @nargs: the number of arguments
8670 *
8671 * Implement the namespace-uri() XPath function
8672 * string namespace-uri(node-set?)
8673 * The namespace-uri function returns a string containing the
8674 * namespace URI of the expanded name of the node in the argument
8675 * node-set that is first in document order. If the node-set is empty,
8676 * the first node has no name, or the expanded name has no namespace
8677 * URI, an empty string is returned. If the argument is omitted it
8678 * defaults to the context node.
8679 */
8680void
8681xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8682 xmlXPathObjectPtr cur;
8683
Daniel Veillarda82b1822004-11-08 16:24:57 +00008684 if (ctxt == NULL) return;
8685
Owen Taylor3473f882001-02-23 17:55:21 +00008686 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008687 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8688 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008689 nargs = 1;
8690 }
8691 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008692 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008693 ((ctxt->value->type != XPATH_NODESET) &&
8694 (ctxt->value->type != XPATH_XSLT_TREE)))
8695 XP_ERROR(XPATH_INVALID_TYPE);
8696 cur = valuePop(ctxt);
8697
Daniel Veillard911f49a2001-04-07 15:39:35 +00008698 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008699 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008700 } else {
8701 int i = 0; /* Should be first in document order !!!!! */
8702 switch (cur->nodesetval->nodeTab[i]->type) {
8703 case XML_ELEMENT_NODE:
8704 case XML_ATTRIBUTE_NODE:
8705 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008706 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008707 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008708 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008709 cur->nodesetval->nodeTab[i]->ns->href));
8710 break;
8711 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008712 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008713 }
8714 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008715 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008716}
8717
8718/**
8719 * xmlXPathNameFunction:
8720 * @ctxt: the XPath Parser context
8721 * @nargs: the number of arguments
8722 *
8723 * Implement the name() XPath function
8724 * string name(node-set?)
8725 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008726 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00008727 * order. The QName must represent the name with respect to the namespace
8728 * declarations in effect on the node whose name is being represented.
8729 * Typically, this will be the form in which the name occurred in the XML
8730 * source. This need not be the case if there are namespace declarations
8731 * in effect on the node that associate multiple prefixes with the same
8732 * namespace. However, an implementation may include information about
8733 * the original prefix in its representation of nodes; in this case, an
8734 * implementation can ensure that the returned string is always the same
8735 * as the QName used in the XML source. If the argument it omitted it
8736 * defaults to the context node.
8737 * Libxml keep the original prefix so the "real qualified name" used is
8738 * returned.
8739 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008740static void
Daniel Veillard04383752001-07-08 14:27:15 +00008741xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8742{
Owen Taylor3473f882001-02-23 17:55:21 +00008743 xmlXPathObjectPtr cur;
8744
8745 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008746 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8747 ctxt->context->node));
Daniel Veillard04383752001-07-08 14:27:15 +00008748 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008749 }
8750
8751 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00008752 if ((ctxt->value == NULL) ||
8753 ((ctxt->value->type != XPATH_NODESET) &&
8754 (ctxt->value->type != XPATH_XSLT_TREE)))
8755 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00008756 cur = valuePop(ctxt);
8757
Daniel Veillard911f49a2001-04-07 15:39:35 +00008758 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008759 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008760 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00008761 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00008762
Daniel Veillard04383752001-07-08 14:27:15 +00008763 switch (cur->nodesetval->nodeTab[i]->type) {
8764 case XML_ELEMENT_NODE:
8765 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008766 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008767 valuePush(ctxt,
8768 xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008769 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8770 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008771 valuePush(ctxt,
8772 xmlXPathCacheNewString(ctxt->context,
8773 cur->nodesetval->nodeTab[i]->name));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008774 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00008775 xmlChar *fullname;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008776
Daniel Veillardc00cda82003-04-07 10:22:39 +00008777 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8778 cur->nodesetval->nodeTab[i]->ns->prefix,
8779 NULL, 0);
8780 if (fullname == cur->nodesetval->nodeTab[i]->name)
8781 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8782 if (fullname == NULL) {
8783 XP_ERROR(XPATH_MEMORY_ERROR);
8784 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008785 valuePush(ctxt, xmlXPathCacheWrapString(
8786 ctxt->context, fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00008787 }
8788 break;
8789 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008790 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8791 cur->nodesetval->nodeTab[i]));
Daniel Veillard04383752001-07-08 14:27:15 +00008792 xmlXPathLocalNameFunction(ctxt, 1);
8793 }
Owen Taylor3473f882001-02-23 17:55:21 +00008794 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008795 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008796}
8797
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008798
8799/**
Owen Taylor3473f882001-02-23 17:55:21 +00008800 * xmlXPathStringFunction:
8801 * @ctxt: the XPath Parser context
8802 * @nargs: the number of arguments
8803 *
8804 * Implement the string() XPath function
8805 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00008806 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00008807 * - A node-set is converted to a string by returning the value of
8808 * the node in the node-set that is first in document order.
8809 * If the node-set is empty, an empty string is returned.
8810 * - A number is converted to a string as follows
Daniel Veillard45490ae2008-07-29 09:13:19 +00008811 * + NaN is converted to the string NaN
8812 * + positive zero is converted to the string 0
8813 * + negative zero is converted to the string 0
8814 * + positive infinity is converted to the string Infinity
8815 * + negative infinity is converted to the string -Infinity
Owen Taylor3473f882001-02-23 17:55:21 +00008816 * + if the number is an integer, the number is represented in
8817 * decimal form as a Number with no decimal point and no leading
8818 * zeros, preceded by a minus sign (-) if the number is negative
8819 * + otherwise, the number is represented in decimal form as a
8820 * Number including a decimal point with at least one digit
8821 * before the decimal point and at least one digit after the
8822 * decimal point, preceded by a minus sign (-) if the number
8823 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008824 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00008825 * before the decimal point; beyond the one required digit
8826 * after the decimal point there must be as many, but only as
8827 * many, more digits as are needed to uniquely distinguish the
8828 * number from all other IEEE 754 numeric values.
8829 * - The boolean false value is converted to the string false.
8830 * The boolean true value is converted to the string true.
8831 *
8832 * If the argument is omitted, it defaults to a node-set with the
8833 * context node as its only member.
8834 */
8835void
8836xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8837 xmlXPathObjectPtr cur;
8838
Daniel Veillarda82b1822004-11-08 16:24:57 +00008839 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008840 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008841 valuePush(ctxt,
8842 xmlXPathCacheWrapString(ctxt->context,
8843 xmlXPathCastNodeToString(ctxt->context->node)));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008844 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008845 }
8846
8847 CHECK_ARITY(1);
8848 cur = valuePop(ctxt);
8849 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008850 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00008851}
8852
8853/**
8854 * xmlXPathStringLengthFunction:
8855 * @ctxt: the XPath Parser context
8856 * @nargs: the number of arguments
8857 *
8858 * Implement the string-length() XPath function
8859 * number string-length(string?)
8860 * The string-length returns the number of characters in the string
8861 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8862 * the context node converted to a string, in other words the value
8863 * of the context node.
8864 */
8865void
8866xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8867 xmlXPathObjectPtr cur;
8868
8869 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008870 if ((ctxt == NULL) || (ctxt->context == NULL))
8871 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008872 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008873 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008874 } else {
8875 xmlChar *content;
8876
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008877 content = xmlXPathCastNodeToString(ctxt->context->node);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008878 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8879 xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00008880 xmlFree(content);
8881 }
8882 return;
8883 }
8884 CHECK_ARITY(1);
8885 CAST_TO_STRING;
8886 CHECK_TYPE(XPATH_STRING);
8887 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008888 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
Daniel Veillard45490ae2008-07-29 09:13:19 +00008889 xmlUTF8Strlen(cur->stringval)));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008890 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008891}
8892
8893/**
8894 * xmlXPathConcatFunction:
8895 * @ctxt: the XPath Parser context
8896 * @nargs: the number of arguments
8897 *
8898 * Implement the concat() XPath function
8899 * string concat(string, string, string*)
8900 * The concat function returns the concatenation of its arguments.
8901 */
8902void
8903xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8904 xmlXPathObjectPtr cur, newobj;
8905 xmlChar *tmp;
8906
Daniel Veillarda82b1822004-11-08 16:24:57 +00008907 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008908 if (nargs < 2) {
8909 CHECK_ARITY(2);
8910 }
8911
8912 CAST_TO_STRING;
8913 cur = valuePop(ctxt);
8914 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008915 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008916 return;
8917 }
8918 nargs--;
8919
8920 while (nargs > 0) {
8921 CAST_TO_STRING;
8922 newobj = valuePop(ctxt);
8923 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008924 xmlXPathReleaseObject(ctxt->context, newobj);
8925 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008926 XP_ERROR(XPATH_INVALID_TYPE);
8927 }
8928 tmp = xmlStrcat(newobj->stringval, cur->stringval);
8929 newobj->stringval = cur->stringval;
8930 cur->stringval = tmp;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008931 xmlXPathReleaseObject(ctxt->context, newobj);
Owen Taylor3473f882001-02-23 17:55:21 +00008932 nargs--;
8933 }
8934 valuePush(ctxt, cur);
8935}
8936
8937/**
8938 * xmlXPathContainsFunction:
8939 * @ctxt: the XPath Parser context
8940 * @nargs: the number of arguments
8941 *
8942 * Implement the contains() XPath function
8943 * boolean contains(string, string)
8944 * The contains function returns true if the first argument string
8945 * contains the second argument string, and otherwise returns false.
8946 */
8947void
8948xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8949 xmlXPathObjectPtr hay, needle;
8950
8951 CHECK_ARITY(2);
8952 CAST_TO_STRING;
8953 CHECK_TYPE(XPATH_STRING);
8954 needle = valuePop(ctxt);
8955 CAST_TO_STRING;
8956 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008957
Owen Taylor3473f882001-02-23 17:55:21 +00008958 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008959 xmlXPathReleaseObject(ctxt->context, hay);
8960 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008961 XP_ERROR(XPATH_INVALID_TYPE);
8962 }
8963 if (xmlStrstr(hay->stringval, needle->stringval))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008964 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00008965 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008966 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8967 xmlXPathReleaseObject(ctxt->context, hay);
8968 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008969}
8970
8971/**
8972 * xmlXPathStartsWithFunction:
8973 * @ctxt: the XPath Parser context
8974 * @nargs: the number of arguments
8975 *
8976 * Implement the starts-with() XPath function
8977 * boolean starts-with(string, string)
8978 * The starts-with function returns true if the first argument string
8979 * starts with the second argument string, and otherwise returns false.
8980 */
8981void
8982xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8983 xmlXPathObjectPtr hay, needle;
8984 int n;
8985
8986 CHECK_ARITY(2);
8987 CAST_TO_STRING;
8988 CHECK_TYPE(XPATH_STRING);
8989 needle = valuePop(ctxt);
8990 CAST_TO_STRING;
8991 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008992
Owen Taylor3473f882001-02-23 17:55:21 +00008993 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008994 xmlXPathReleaseObject(ctxt->context, hay);
8995 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008996 XP_ERROR(XPATH_INVALID_TYPE);
8997 }
8998 n = xmlStrlen(needle->stringval);
8999 if (xmlStrncmp(hay->stringval, needle->stringval, n))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009000 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009001 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009002 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9003 xmlXPathReleaseObject(ctxt->context, hay);
9004 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009005}
9006
9007/**
9008 * xmlXPathSubstringFunction:
9009 * @ctxt: the XPath Parser context
9010 * @nargs: the number of arguments
9011 *
9012 * Implement the substring() XPath function
9013 * string substring(string, number, number?)
9014 * The substring function returns the substring of the first argument
9015 * starting at the position specified in the second argument with
9016 * length specified in the third argument. For example,
9017 * substring("12345",2,3) returns "234". If the third argument is not
9018 * specified, it returns the substring starting at the position specified
9019 * in the second argument and continuing to the end of the string. For
9020 * example, substring("12345",2) returns "2345". More precisely, each
9021 * character in the string (see [3.6 Strings]) is considered to have a
9022 * numeric position: the position of the first character is 1, the position
9023 * of the second character is 2 and so on. The returned substring contains
9024 * those characters for which the position of the character is greater than
9025 * or equal to the second argument and, if the third argument is specified,
9026 * less than the sum of the second and third arguments; the comparisons
9027 * and addition used for the above follow the standard IEEE 754 rules. Thus:
Daniel Veillard45490ae2008-07-29 09:13:19 +00009028 * - substring("12345", 1.5, 2.6) returns "234"
9029 * - substring("12345", 0, 3) returns "12"
9030 * - substring("12345", 0 div 0, 3) returns ""
9031 * - substring("12345", 1, 0 div 0) returns ""
9032 * - substring("12345", -42, 1 div 0) returns "12345"
9033 * - substring("12345", -1 div 0, 1 div 0) returns ""
Owen Taylor3473f882001-02-23 17:55:21 +00009034 */
9035void
9036xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9037 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009038 double le=0, in;
9039 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00009040 xmlChar *ret;
9041
Owen Taylor3473f882001-02-23 17:55:21 +00009042 if (nargs < 2) {
9043 CHECK_ARITY(2);
9044 }
9045 if (nargs > 3) {
9046 CHECK_ARITY(3);
9047 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009048 /*
9049 * take care of possible last (position) argument
9050 */
Owen Taylor3473f882001-02-23 17:55:21 +00009051 if (nargs == 3) {
9052 CAST_TO_NUMBER;
9053 CHECK_TYPE(XPATH_NUMBER);
9054 len = valuePop(ctxt);
9055 le = len->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009056 xmlXPathReleaseObject(ctxt->context, len);
Owen Taylor3473f882001-02-23 17:55:21 +00009057 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009058
Owen Taylor3473f882001-02-23 17:55:21 +00009059 CAST_TO_NUMBER;
9060 CHECK_TYPE(XPATH_NUMBER);
9061 start = valuePop(ctxt);
9062 in = start->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009063 xmlXPathReleaseObject(ctxt->context, start);
Owen Taylor3473f882001-02-23 17:55:21 +00009064 CAST_TO_STRING;
9065 CHECK_TYPE(XPATH_STRING);
9066 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00009067 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00009068
Daniel Veillard97ac1312001-05-30 19:14:17 +00009069 /*
9070 * If last pos not present, calculate last position
9071 */
Daniel Veillard9e412302002-06-10 15:59:44 +00009072 if (nargs != 3) {
9073 le = (double)m;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009074 if (in < 1.0)
Daniel Veillard9e412302002-06-10 15:59:44 +00009075 in = 1.0;
9076 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009077
Daniel Veillard45490ae2008-07-29 09:13:19 +00009078 /* Need to check for the special cases where either
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009079 * the index is NaN, the length is NaN, or both
9080 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00009081 */
Daniel Veillard48b3eb22009-03-25 09:51:19 +00009082 if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009083 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00009084 * To meet the requirements of the spec, the arguments
Daniel Veillard45490ae2008-07-29 09:13:19 +00009085 * must be converted to integer format before
Daniel Veillard9e412302002-06-10 15:59:44 +00009086 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009087 *
Daniel Veillard9e412302002-06-10 15:59:44 +00009088 * First we go to integer form, rounding up
9089 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009090 */
9091 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00009092 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00009093
Daniel Veillard9e412302002-06-10 15:59:44 +00009094 if (xmlXPathIsInf(le) == 1) {
9095 l = m;
9096 if (i < 1)
9097 i = 1;
9098 }
9099 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9100 l = 0;
9101 else {
9102 l = (int) le;
9103 if (((double)l)+0.5 <= le) l++;
9104 }
9105
9106 /* Now we normalize inidices */
9107 i -= 1;
9108 l += i;
9109 if (i < 0)
9110 i = 0;
9111 if (l > m)
9112 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00009113
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009114 /* number of chars to copy */
9115 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00009116
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009117 ret = xmlUTF8Strsub(str->stringval, i, l);
9118 }
9119 else {
9120 ret = NULL;
9121 }
Owen Taylor3473f882001-02-23 17:55:21 +00009122 if (ret == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009123 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00009124 else {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009125 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009126 xmlFree(ret);
9127 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009128 xmlXPathReleaseObject(ctxt->context, str);
Owen Taylor3473f882001-02-23 17:55:21 +00009129}
9130
9131/**
9132 * xmlXPathSubstringBeforeFunction:
9133 * @ctxt: the XPath Parser context
9134 * @nargs: the number of arguments
9135 *
9136 * Implement the substring-before() XPath function
9137 * string substring-before(string, string)
9138 * The substring-before function returns the substring of the first
9139 * argument string that precedes the first occurrence of the second
9140 * argument string in the first argument string, or the empty string
9141 * if the first argument string does not contain the second argument
9142 * string. For example, substring-before("1999/04/01","/") returns 1999.
9143 */
9144void
9145xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9146 xmlXPathObjectPtr str;
9147 xmlXPathObjectPtr find;
Daniel Veillardade10f22012-07-12 09:43:27 +08009148 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009149 const xmlChar *point;
9150 int offset;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009151
Owen Taylor3473f882001-02-23 17:55:21 +00009152 CHECK_ARITY(2);
9153 CAST_TO_STRING;
9154 find = valuePop(ctxt);
9155 CAST_TO_STRING;
9156 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009157
Daniel Veillardade10f22012-07-12 09:43:27 +08009158 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009159 if (target) {
9160 point = xmlStrstr(str->stringval, find->stringval);
9161 if (point) {
9162 offset = (int)(point - str->stringval);
Daniel Veillardade10f22012-07-12 09:43:27 +08009163 xmlBufAdd(target, str->stringval, offset);
Owen Taylor3473f882001-02-23 17:55:21 +00009164 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009165 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009166 xmlBufContent(target)));
9167 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009168 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009169 xmlXPathReleaseObject(ctxt->context, str);
9170 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009171}
9172
9173/**
9174 * xmlXPathSubstringAfterFunction:
9175 * @ctxt: the XPath Parser context
9176 * @nargs: the number of arguments
9177 *
9178 * Implement the substring-after() XPath function
9179 * string substring-after(string, string)
9180 * The substring-after function returns the substring of the first
9181 * argument string that follows the first occurrence of the second
9182 * argument string in the first argument string, or the empty stringi
9183 * if the first argument string does not contain the second argument
9184 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9185 * and substring-after("1999/04/01","19") returns 99/04/01.
9186 */
9187void
9188xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9189 xmlXPathObjectPtr str;
9190 xmlXPathObjectPtr find;
Daniel Veillardade10f22012-07-12 09:43:27 +08009191 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009192 const xmlChar *point;
9193 int offset;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009194
Owen Taylor3473f882001-02-23 17:55:21 +00009195 CHECK_ARITY(2);
9196 CAST_TO_STRING;
9197 find = valuePop(ctxt);
9198 CAST_TO_STRING;
9199 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009200
Daniel Veillardade10f22012-07-12 09:43:27 +08009201 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009202 if (target) {
9203 point = xmlStrstr(str->stringval, find->stringval);
9204 if (point) {
9205 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
Daniel Veillardade10f22012-07-12 09:43:27 +08009206 xmlBufAdd(target, &str->stringval[offset],
Owen Taylor3473f882001-02-23 17:55:21 +00009207 xmlStrlen(str->stringval) - offset);
9208 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009209 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009210 xmlBufContent(target)));
9211 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009212 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009213 xmlXPathReleaseObject(ctxt->context, str);
9214 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009215}
9216
9217/**
9218 * xmlXPathNormalizeFunction:
9219 * @ctxt: the XPath Parser context
9220 * @nargs: the number of arguments
9221 *
9222 * Implement the normalize-space() XPath function
9223 * string normalize-space(string?)
9224 * The normalize-space function returns the argument string with white
9225 * space normalized by stripping leading and trailing whitespace
9226 * and replacing sequences of whitespace characters by a single
9227 * space. Whitespace characters are the same allowed by the S production
9228 * in XML. If the argument is omitted, it defaults to the context
9229 * node converted to a string, in other words the value of the context node.
9230 */
9231void
9232xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9233 xmlXPathObjectPtr obj = NULL;
9234 xmlChar *source = NULL;
Daniel Veillardade10f22012-07-12 09:43:27 +08009235 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009236 xmlChar blank;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009237
Daniel Veillarda82b1822004-11-08 16:24:57 +00009238 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009239 if (nargs == 0) {
9240 /* Use current context node */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009241 valuePush(ctxt,
9242 xmlXPathCacheWrapString(ctxt->context,
9243 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00009244 nargs = 1;
9245 }
9246
9247 CHECK_ARITY(1);
9248 CAST_TO_STRING;
9249 CHECK_TYPE(XPATH_STRING);
9250 obj = valuePop(ctxt);
9251 source = obj->stringval;
9252
Daniel Veillardade10f22012-07-12 09:43:27 +08009253 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009254 if (target && source) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00009255
Owen Taylor3473f882001-02-23 17:55:21 +00009256 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00009257 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00009258 source++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009259
Owen Taylor3473f882001-02-23 17:55:21 +00009260 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9261 blank = 0;
9262 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00009263 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009264 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00009265 } else {
9266 if (blank) {
Daniel Veillardade10f22012-07-12 09:43:27 +08009267 xmlBufAdd(target, &blank, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00009268 blank = 0;
9269 }
Daniel Veillardade10f22012-07-12 09:43:27 +08009270 xmlBufAdd(target, source, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00009271 }
9272 source++;
9273 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009274 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009275 xmlBufContent(target)));
9276 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009277 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009278 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00009279}
9280
9281/**
9282 * xmlXPathTranslateFunction:
9283 * @ctxt: the XPath Parser context
9284 * @nargs: the number of arguments
9285 *
9286 * Implement the translate() XPath function
9287 * string translate(string, string, string)
9288 * The translate function returns the first argument string with
9289 * occurrences of characters in the second argument string replaced
9290 * by the character at the corresponding position in the third argument
9291 * string. For example, translate("bar","abc","ABC") returns the string
9292 * BAr. If there is a character in the second argument string with no
9293 * character at a corresponding position in the third argument string
9294 * (because the second argument string is longer than the third argument
9295 * string), then occurrences of that character in the first argument
9296 * string are removed. For example, translate("--aaa--","abc-","ABC")
9297 * returns "AAA". If a character occurs more than once in second
9298 * argument string, then the first occurrence determines the replacement
9299 * character. If the third argument string is longer than the second
9300 * argument string, then excess characters are ignored.
9301 */
9302void
9303xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00009304 xmlXPathObjectPtr str;
9305 xmlXPathObjectPtr from;
9306 xmlXPathObjectPtr to;
Daniel Veillardade10f22012-07-12 09:43:27 +08009307 xmlBufPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009308 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009309 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00009310 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009311 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00009312
Daniel Veillarde043ee12001-04-16 14:08:07 +00009313 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00009314
Daniel Veillarde043ee12001-04-16 14:08:07 +00009315 CAST_TO_STRING;
9316 to = valuePop(ctxt);
9317 CAST_TO_STRING;
9318 from = valuePop(ctxt);
9319 CAST_TO_STRING;
9320 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009321
Daniel Veillardade10f22012-07-12 09:43:27 +08009322 target = xmlBufCreate();
Daniel Veillarde043ee12001-04-16 14:08:07 +00009323 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009324 max = xmlUTF8Strlen(to->stringval);
9325 for (cptr = str->stringval; (ch=*cptr); ) {
9326 offset = xmlUTF8Strloc(from->stringval, cptr);
9327 if (offset >= 0) {
9328 if (offset < max) {
9329 point = xmlUTF8Strpos(to->stringval, offset);
9330 if (point)
Daniel Veillardade10f22012-07-12 09:43:27 +08009331 xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
Daniel Veillard97ac1312001-05-30 19:14:17 +00009332 }
9333 } else
Daniel Veillardade10f22012-07-12 09:43:27 +08009334 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
Daniel Veillard97ac1312001-05-30 19:14:17 +00009335
9336 /* Step to next character in input */
9337 cptr++;
9338 if ( ch & 0x80 ) {
9339 /* if not simple ascii, verify proper format */
9340 if ( (ch & 0xc0) != 0xc0 ) {
9341 xmlGenericError(xmlGenericErrorContext,
9342 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08009343 /* not asserting an XPath error is probably better */
Daniel Veillard97ac1312001-05-30 19:14:17 +00009344 break;
9345 }
9346 /* then skip over remaining bytes for this char */
9347 while ( (ch <<= 1) & 0x80 )
9348 if ( (*cptr++ & 0xc0) != 0x80 ) {
9349 xmlGenericError(xmlGenericErrorContext,
9350 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08009351 /* not asserting an XPath error is probably better */
Daniel Veillard97ac1312001-05-30 19:14:17 +00009352 break;
9353 }
9354 if (ch & 0x80) /* must have had error encountered */
9355 break;
9356 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00009357 }
Owen Taylor3473f882001-02-23 17:55:21 +00009358 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009359 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009360 xmlBufContent(target)));
9361 xmlBufFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009362 xmlXPathReleaseObject(ctxt->context, str);
9363 xmlXPathReleaseObject(ctxt->context, from);
9364 xmlXPathReleaseObject(ctxt->context, to);
Owen Taylor3473f882001-02-23 17:55:21 +00009365}
9366
9367/**
9368 * xmlXPathBooleanFunction:
9369 * @ctxt: the XPath Parser context
9370 * @nargs: the number of arguments
9371 *
9372 * Implement the boolean() XPath function
9373 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00009374 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00009375 * - a number is true if and only if it is neither positive or
9376 * negative zero nor NaN
9377 * - a node-set is true if and only if it is non-empty
9378 * - a string is true if and only if its length is non-zero
9379 */
9380void
9381xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9382 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00009383
9384 CHECK_ARITY(1);
9385 cur = valuePop(ctxt);
9386 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009387 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009388 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009389}
9390
9391/**
9392 * xmlXPathNotFunction:
9393 * @ctxt: the XPath Parser context
9394 * @nargs: the number of arguments
9395 *
9396 * Implement the not() XPath function
9397 * boolean not(boolean)
9398 * The not function returns true if its argument is false,
9399 * and false otherwise.
9400 */
9401void
9402xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9403 CHECK_ARITY(1);
9404 CAST_TO_BOOLEAN;
9405 CHECK_TYPE(XPATH_BOOLEAN);
9406 ctxt->value->boolval = ! ctxt->value->boolval;
9407}
9408
9409/**
9410 * xmlXPathTrueFunction:
9411 * @ctxt: the XPath Parser context
9412 * @nargs: the number of arguments
9413 *
9414 * Implement the true() XPath function
9415 * boolean true()
9416 */
9417void
9418xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9419 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009420 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009421}
9422
9423/**
9424 * xmlXPathFalseFunction:
9425 * @ctxt: the XPath Parser context
9426 * @nargs: the number of arguments
9427 *
9428 * Implement the false() XPath function
9429 * boolean false()
9430 */
9431void
9432xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9433 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009434 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009435}
9436
9437/**
9438 * xmlXPathLangFunction:
9439 * @ctxt: the XPath Parser context
9440 * @nargs: the number of arguments
9441 *
9442 * Implement the lang() XPath function
9443 * boolean lang(string)
9444 * The lang function returns true or false depending on whether the
9445 * language of the context node as specified by xml:lang attributes
9446 * is the same as or is a sublanguage of the language specified by
9447 * the argument string. The language of the context node is determined
9448 * by the value of the xml:lang attribute on the context node, or, if
9449 * the context node has no xml:lang attribute, by the value of the
9450 * xml:lang attribute on the nearest ancestor of the context node that
9451 * has an xml:lang attribute. If there is no such attribute, then lang
9452 * returns false. If there is such an attribute, then lang returns
9453 * true if the attribute value is equal to the argument ignoring case,
9454 * or if there is some suffix starting with - such that the attribute
9455 * value is equal to the argument ignoring that suffix of the attribute
9456 * value and ignoring case.
9457 */
9458void
9459xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009460 xmlXPathObjectPtr val = NULL;
9461 const xmlChar *theLang = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009462 const xmlChar *lang;
9463 int ret = 0;
9464 int i;
9465
9466 CHECK_ARITY(1);
9467 CAST_TO_STRING;
9468 CHECK_TYPE(XPATH_STRING);
9469 val = valuePop(ctxt);
9470 lang = val->stringval;
9471 theLang = xmlNodeGetLang(ctxt->context->node);
9472 if ((theLang != NULL) && (lang != NULL)) {
9473 for (i = 0;lang[i] != 0;i++)
9474 if (toupper(lang[i]) != toupper(theLang[i]))
9475 goto not_equal;
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009476 if ((theLang[i] == 0) || (theLang[i] == '-'))
9477 ret = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009478 }
9479not_equal:
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009480 if (theLang != NULL)
9481 xmlFree((void *)theLang);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009482
9483 xmlXPathReleaseObject(ctxt->context, val);
9484 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009485}
9486
9487/**
9488 * xmlXPathNumberFunction:
9489 * @ctxt: the XPath Parser context
9490 * @nargs: the number of arguments
9491 *
9492 * Implement the number() XPath function
9493 * number number(object?)
9494 */
9495void
9496xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9497 xmlXPathObjectPtr cur;
9498 double res;
9499
Daniel Veillarda82b1822004-11-08 16:24:57 +00009500 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009501 if (nargs == 0) {
9502 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009503 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
Owen Taylor3473f882001-02-23 17:55:21 +00009504 } else {
9505 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9506
9507 res = xmlXPathStringEvalNumber(content);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009508 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
Owen Taylor3473f882001-02-23 17:55:21 +00009509 xmlFree(content);
9510 }
9511 return;
9512 }
9513
9514 CHECK_ARITY(1);
9515 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009516 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00009517}
9518
9519/**
9520 * xmlXPathSumFunction:
9521 * @ctxt: the XPath Parser context
9522 * @nargs: the number of arguments
9523 *
9524 * Implement the sum() XPath function
9525 * number sum(node-set)
9526 * The sum function returns the sum of the values of the nodes in
9527 * the argument node-set.
9528 */
9529void
9530xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9531 xmlXPathObjectPtr cur;
9532 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009533 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00009534
9535 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009536 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009537 ((ctxt->value->type != XPATH_NODESET) &&
9538 (ctxt->value->type != XPATH_XSLT_TREE)))
9539 XP_ERROR(XPATH_INVALID_TYPE);
9540 cur = valuePop(ctxt);
9541
William M. Brack08171912003-12-29 02:52:11 +00009542 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009543 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9544 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00009545 }
9546 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009547 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9548 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009549}
9550
William M. Brack3d426662005-04-19 14:40:28 +00009551/*
9552 * To assure working code on multiple platforms, we want to only depend
9553 * upon the characteristic truncation of converting a floating point value
9554 * to an integer. Unfortunately, because of the different storage sizes
9555 * of our internal floating point value (double) and integer (int), we
9556 * can't directly convert (see bug 301162). This macro is a messy
9557 * 'workaround'
9558 */
9559#define XTRUNC(f, v) \
9560 f = fmod((v), INT_MAX); \
9561 f = (v) - (f) + (double)((int)(f));
9562
Owen Taylor3473f882001-02-23 17:55:21 +00009563/**
9564 * xmlXPathFloorFunction:
9565 * @ctxt: the XPath Parser context
9566 * @nargs: the number of arguments
9567 *
9568 * Implement the floor() XPath function
9569 * number floor(number)
9570 * The floor function returns the largest (closest to positive infinity)
9571 * number that is not greater than the argument and that is an integer.
9572 */
9573void
9574xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009575 double f;
9576
Owen Taylor3473f882001-02-23 17:55:21 +00009577 CHECK_ARITY(1);
9578 CAST_TO_NUMBER;
9579 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009580
William M. Brack3d426662005-04-19 14:40:28 +00009581 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009582 if (f != ctxt->value->floatval) {
9583 if (ctxt->value->floatval > 0)
9584 ctxt->value->floatval = f;
9585 else
9586 ctxt->value->floatval = f - 1;
9587 }
Owen Taylor3473f882001-02-23 17:55:21 +00009588}
9589
9590/**
9591 * xmlXPathCeilingFunction:
9592 * @ctxt: the XPath Parser context
9593 * @nargs: the number of arguments
9594 *
9595 * Implement the ceiling() XPath function
9596 * number ceiling(number)
9597 * The ceiling function returns the smallest (closest to negative infinity)
9598 * number that is not less than the argument and that is an integer.
9599 */
9600void
9601xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9602 double f;
9603
9604 CHECK_ARITY(1);
9605 CAST_TO_NUMBER;
9606 CHECK_TYPE(XPATH_NUMBER);
9607
9608#if 0
9609 ctxt->value->floatval = ceil(ctxt->value->floatval);
9610#else
William M. Brack3d426662005-04-19 14:40:28 +00009611 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009612 if (f != ctxt->value->floatval) {
9613 if (ctxt->value->floatval > 0)
9614 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009615 else {
9616 if (ctxt->value->floatval < 0 && f == 0)
9617 ctxt->value->floatval = xmlXPathNZERO;
9618 else
9619 ctxt->value->floatval = f;
9620 }
9621
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009622 }
Owen Taylor3473f882001-02-23 17:55:21 +00009623#endif
9624}
9625
9626/**
9627 * xmlXPathRoundFunction:
9628 * @ctxt: the XPath Parser context
9629 * @nargs: the number of arguments
9630 *
9631 * Implement the round() XPath function
9632 * number round(number)
9633 * The round function returns the number that is closest to the
9634 * argument and that is an integer. If there are two such numbers,
9635 * then the one that is even is returned.
9636 */
9637void
9638xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9639 double f;
9640
9641 CHECK_ARITY(1);
9642 CAST_TO_NUMBER;
9643 CHECK_TYPE(XPATH_NUMBER);
9644
Daniel Veillardcda96922001-08-21 10:56:31 +00009645 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9646 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9647 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009648 (ctxt->value->floatval == 0.0))
9649 return;
9650
William M. Brack3d426662005-04-19 14:40:28 +00009651 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009652 if (ctxt->value->floatval < 0) {
9653 if (ctxt->value->floatval < f - 0.5)
9654 ctxt->value->floatval = f - 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009655 else
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009656 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009657 if (ctxt->value->floatval == 0)
9658 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009659 } else {
9660 if (ctxt->value->floatval < f + 0.5)
9661 ctxt->value->floatval = f;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009662 else
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009663 ctxt->value->floatval = f + 1;
9664 }
Owen Taylor3473f882001-02-23 17:55:21 +00009665}
9666
9667/************************************************************************
9668 * *
9669 * The Parser *
9670 * *
9671 ************************************************************************/
9672
9673/*
William M. Brack08171912003-12-29 02:52:11 +00009674 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00009675 * implementation.
9676 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009677static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009678static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009679static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009680static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00009681static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9682 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00009683
9684/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00009685 * xmlXPathCurrentChar:
9686 * @ctxt: the XPath parser context
9687 * @cur: pointer to the beginning of the char
9688 * @len: pointer to the length of the char read
9689 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009690 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00009691 * bytes in the input buffer.
9692 *
Daniel Veillard60087f32001-10-10 09:45:09 +00009693 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00009694 */
9695
9696static int
9697xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9698 unsigned char c;
9699 unsigned int val;
9700 const xmlChar *cur;
9701
9702 if (ctxt == NULL)
9703 return(0);
9704 cur = ctxt->cur;
9705
9706 /*
9707 * We are supposed to handle UTF8, check it's valid
9708 * From rfc2044: encoding of the Unicode values on UTF-8:
9709 *
9710 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9711 * 0000 0000-0000 007F 0xxxxxxx
9712 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
Daniel Veillard45490ae2008-07-29 09:13:19 +00009713 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
Daniel Veillard61d80a22001-04-27 17:13:01 +00009714 *
9715 * Check for the 0x110000 limit too
9716 */
9717 c = *cur;
9718 if (c & 0x80) {
9719 if ((cur[1] & 0xc0) != 0x80)
9720 goto encoding_error;
9721 if ((c & 0xe0) == 0xe0) {
9722
9723 if ((cur[2] & 0xc0) != 0x80)
9724 goto encoding_error;
9725 if ((c & 0xf0) == 0xf0) {
9726 if (((c & 0xf8) != 0xf0) ||
9727 ((cur[3] & 0xc0) != 0x80))
9728 goto encoding_error;
9729 /* 4-byte code */
9730 *len = 4;
9731 val = (cur[0] & 0x7) << 18;
9732 val |= (cur[1] & 0x3f) << 12;
9733 val |= (cur[2] & 0x3f) << 6;
9734 val |= cur[3] & 0x3f;
9735 } else {
9736 /* 3-byte code */
9737 *len = 3;
9738 val = (cur[0] & 0xf) << 12;
9739 val |= (cur[1] & 0x3f) << 6;
9740 val |= cur[2] & 0x3f;
9741 }
9742 } else {
9743 /* 2-byte code */
9744 *len = 2;
9745 val = (cur[0] & 0x1f) << 6;
9746 val |= cur[1] & 0x3f;
9747 }
9748 if (!IS_CHAR(val)) {
9749 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009750 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00009751 return(val);
9752 } else {
9753 /* 1-byte code */
9754 *len = 1;
9755 return((int) *cur);
9756 }
9757encoding_error:
9758 /*
William M. Brack08171912003-12-29 02:52:11 +00009759 * If we detect an UTF8 error that probably means that the
9760 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00009761 * declaration header. Report the error and switch the encoding
9762 * to ISO-Latin-1 (if you don't like this policy, just declare the
9763 * encoding !)
9764 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00009765 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00009766 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009767}
9768
9769/**
Owen Taylor3473f882001-02-23 17:55:21 +00009770 * xmlXPathParseNCName:
9771 * @ctxt: the XPath Parser context
9772 *
9773 * parse an XML namespace non qualified name.
9774 *
9775 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9776 *
9777 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9778 * CombiningChar | Extender
9779 *
9780 * Returns the namespace name or NULL
9781 */
9782
9783xmlChar *
9784xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00009785 const xmlChar *in;
9786 xmlChar *ret;
9787 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009788
Daniel Veillarda82b1822004-11-08 16:24:57 +00009789 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00009790 /*
9791 * Accelerator for simple ASCII names
9792 */
9793 in = ctxt->cur;
9794 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9795 ((*in >= 0x41) && (*in <= 0x5A)) ||
9796 (*in == '_')) {
9797 in++;
9798 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9799 ((*in >= 0x41) && (*in <= 0x5A)) ||
9800 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00009801 (*in == '_') || (*in == '.') ||
9802 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00009803 in++;
9804 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9805 (*in == '[') || (*in == ']') || (*in == ':') ||
9806 (*in == '@') || (*in == '*')) {
9807 count = in - ctxt->cur;
9808 if (count == 0)
9809 return(NULL);
9810 ret = xmlStrndup(ctxt->cur, count);
9811 ctxt->cur = in;
9812 return(ret);
9813 }
9814 }
9815 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009816}
9817
Daniel Veillard2156a562001-04-28 12:24:34 +00009818
Owen Taylor3473f882001-02-23 17:55:21 +00009819/**
9820 * xmlXPathParseQName:
9821 * @ctxt: the XPath Parser context
Daniel Veillard45490ae2008-07-29 09:13:19 +00009822 * @prefix: a xmlChar **
Owen Taylor3473f882001-02-23 17:55:21 +00009823 *
9824 * parse an XML qualified name
9825 *
9826 * [NS 5] QName ::= (Prefix ':')? LocalPart
9827 *
9828 * [NS 6] Prefix ::= NCName
9829 *
9830 * [NS 7] LocalPart ::= NCName
9831 *
9832 * Returns the function returns the local part, and prefix is updated
9833 * to get the Prefix if any.
9834 */
9835
Daniel Veillard56a4cb82001-03-24 17:00:36 +00009836static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00009837xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9838 xmlChar *ret = NULL;
9839
9840 *prefix = NULL;
9841 ret = xmlXPathParseNCName(ctxt);
Daniel Veillard074f37e2008-09-01 13:38:22 +00009842 if (ret && CUR == ':') {
Owen Taylor3473f882001-02-23 17:55:21 +00009843 *prefix = ret;
9844 NEXT;
9845 ret = xmlXPathParseNCName(ctxt);
9846 }
9847 return(ret);
9848}
9849
9850/**
9851 * xmlXPathParseName:
9852 * @ctxt: the XPath Parser context
9853 *
9854 * parse an XML name
9855 *
9856 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9857 * CombiningChar | Extender
9858 *
9859 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9860 *
9861 * Returns the namespace name or NULL
9862 */
9863
9864xmlChar *
9865xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009866 const xmlChar *in;
9867 xmlChar *ret;
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009868 size_t count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009869
Daniel Veillarda82b1822004-11-08 16:24:57 +00009870 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009871 /*
9872 * Accelerator for simple ASCII names
9873 */
9874 in = ctxt->cur;
9875 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9876 ((*in >= 0x41) && (*in <= 0x5A)) ||
9877 (*in == '_') || (*in == ':')) {
9878 in++;
9879 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9880 ((*in >= 0x41) && (*in <= 0x5A)) ||
9881 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00009882 (*in == '_') || (*in == '-') ||
9883 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00009884 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00009885 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009886 count = in - ctxt->cur;
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009887 if (count > XML_MAX_NAME_LENGTH) {
9888 ctxt->cur = in;
9889 XP_ERRORNULL(XPATH_EXPR_ERROR);
9890 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00009891 ret = xmlStrndup(ctxt->cur, count);
9892 ctxt->cur = in;
9893 return(ret);
9894 }
9895 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009896 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009897}
9898
Daniel Veillard61d80a22001-04-27 17:13:01 +00009899static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00009900xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009901 xmlChar buf[XML_MAX_NAMELEN + 5];
9902 int len = 0, l;
9903 int c;
9904
9905 /*
9906 * Handler for more complex cases
9907 */
9908 c = CUR_CHAR(l);
9909 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00009910 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9911 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00009912 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00009913 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009914 return(NULL);
9915 }
9916
9917 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9918 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9919 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00009920 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009921 (IS_COMBINING(c)) ||
9922 (IS_EXTENDER(c)))) {
9923 COPY_BUF(l,buf,len,c);
9924 NEXTL(l);
9925 c = CUR_CHAR(l);
9926 if (len >= XML_MAX_NAMELEN) {
9927 /*
9928 * Okay someone managed to make a huge name, so he's ready to pay
9929 * for the processing speed.
9930 */
9931 xmlChar *buffer;
9932 int max = len * 2;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009933
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009934 if (len > XML_MAX_NAME_LENGTH) {
9935 XP_ERRORNULL(XPATH_EXPR_ERROR);
9936 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00009937 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009938 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009939 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009940 }
9941 memcpy(buffer, buf, len);
9942 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9943 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00009944 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009945 (IS_COMBINING(c)) ||
9946 (IS_EXTENDER(c))) {
9947 if (len + 10 > max) {
Daniel Veillardcd852ad2012-07-30 10:12:18 +08009948 if (max > XML_MAX_NAME_LENGTH) {
9949 XP_ERRORNULL(XPATH_EXPR_ERROR);
9950 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00009951 max *= 2;
9952 buffer = (xmlChar *) xmlRealloc(buffer,
9953 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009954 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009955 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009956 }
9957 }
9958 COPY_BUF(l,buffer,len,c);
9959 NEXTL(l);
9960 c = CUR_CHAR(l);
9961 }
9962 buffer[len] = 0;
9963 return(buffer);
9964 }
9965 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009966 if (len == 0)
9967 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009968 return(xmlStrndup(buf, len));
9969}
Daniel Veillard3cd72402002-05-13 10:33:30 +00009970
9971#define MAX_FRAC 20
9972
William M. Brack372a4452004-02-17 13:09:23 +00009973/*
9974 * These are used as divisors for the fractional part of a number.
9975 * Since the table includes 1.0 (representing '0' fractional digits),
9976 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
9977 */
9978static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +00009979 1.0, 10.0, 100.0, 1000.0, 10000.0,
9980 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
9981 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
9982 100000000000000.0,
9983 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +00009984 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +00009985};
9986
Owen Taylor3473f882001-02-23 17:55:21 +00009987/**
9988 * xmlXPathStringEvalNumber:
9989 * @str: A string to scan
9990 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00009991 * [30a] Float ::= Number ('e' Digits?)?
9992 *
Owen Taylor3473f882001-02-23 17:55:21 +00009993 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard45490ae2008-07-29 09:13:19 +00009994 * | '.' Digits
Owen Taylor3473f882001-02-23 17:55:21 +00009995 * [31] Digits ::= [0-9]+
9996 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009997 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00009998 * In complement of the Number expression, this function also handles
9999 * negative values : '-' Number.
10000 *
10001 * Returns the double value.
10002 */
10003double
10004xmlXPathStringEvalNumber(const xmlChar *str) {
10005 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +000010006 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010007 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010008 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010009 int exponent = 0;
10010 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010011#ifdef __GNUC__
10012 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010013 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010014#endif
Daniel Veillardeca82812002-04-24 11:42:02 +000010015 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +000010016 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010017 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
10018 return(xmlXPathNAN);
10019 }
10020 if (*cur == '-') {
10021 isneg = 1;
10022 cur++;
10023 }
Daniel Veillardb06c6142001-08-27 14:26:30 +000010024
10025#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010026 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010027 * tmp/temp is a workaround against a gcc compiler bug
10028 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010029 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010030 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010031 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010032 ret = ret * 10;
10033 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +000010034 ok = 1;
10035 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +000010036 temp = (double) tmp;
10037 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010038 }
Daniel Veillardb06c6142001-08-27 14:26:30 +000010039#else
Daniel Veillard7b416132002-03-07 08:36:03 +000010040 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010041 while ((*cur >= '0') && (*cur <= '9')) {
10042 ret = ret * 10 + (*cur - '0');
10043 ok = 1;
10044 cur++;
10045 }
10046#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010047
Owen Taylor3473f882001-02-23 17:55:21 +000010048 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +000010049 int v, frac = 0;
10050 double fraction = 0;
10051
Owen Taylor3473f882001-02-23 17:55:21 +000010052 cur++;
10053 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10054 return(xmlXPathNAN);
10055 }
Daniel Veillard3cd72402002-05-13 10:33:30 +000010056 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
10057 v = (*cur - '0');
10058 fraction = fraction * 10 + v;
10059 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010060 cur++;
10061 }
Daniel Veillard3cd72402002-05-13 10:33:30 +000010062 fraction /= my_pow10[frac];
10063 ret = ret + fraction;
10064 while ((*cur >= '0') && (*cur <= '9'))
10065 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010066 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010067 if ((*cur == 'e') || (*cur == 'E')) {
10068 cur++;
10069 if (*cur == '-') {
10070 is_exponent_negative = 1;
10071 cur++;
William M. Brack99127052004-05-24 02:52:28 +000010072 } else if (*cur == '+') {
10073 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010074 }
10075 while ((*cur >= '0') && (*cur <= '9')) {
10076 exponent = exponent * 10 + (*cur - '0');
10077 cur++;
10078 }
10079 }
William M. Brack76e95df2003-10-18 16:20:14 +000010080 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010081 if (*cur != 0) return(xmlXPathNAN);
10082 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010083 if (is_exponent_negative) exponent = -exponent;
10084 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +000010085 return(ret);
10086}
10087
10088/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010089 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +000010090 * @ctxt: the XPath Parser context
10091 *
10092 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard45490ae2008-07-29 09:13:19 +000010093 * | '.' Digits
Owen Taylor3473f882001-02-23 17:55:21 +000010094 * [31] Digits ::= [0-9]+
10095 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010096 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +000010097 *
10098 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010099static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010100xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10101{
Owen Taylor3473f882001-02-23 17:55:21 +000010102 double ret = 0.0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010103 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010104 int exponent = 0;
10105 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010106#ifdef __GNUC__
10107 unsigned long tmp = 0;
10108 double temp;
10109#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010110
10111 CHECK_ERROR;
10112 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10113 XP_ERROR(XPATH_NUMBER_ERROR);
10114 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010115#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010116 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010117 * tmp/temp is a workaround against a gcc compiler bug
10118 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010119 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010120 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010121 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010122 ret = ret * 10;
10123 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010124 ok = 1;
10125 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +000010126 temp = (double) tmp;
10127 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010128 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010129#else
10130 ret = 0;
10131 while ((CUR >= '0') && (CUR <= '9')) {
10132 ret = ret * 10 + (CUR - '0');
10133 ok = 1;
10134 NEXT;
10135 }
10136#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010137 if (CUR == '.') {
Phil Shaferee32ad32010-11-03 20:53:55 +010010138 int v, frac = 0;
10139 double fraction = 0;
10140
Owen Taylor3473f882001-02-23 17:55:21 +000010141 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010142 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10143 XP_ERROR(XPATH_NUMBER_ERROR);
10144 }
Phil Shaferee32ad32010-11-03 20:53:55 +010010145 while ((CUR >= '0') && (CUR <= '9') && (frac < MAX_FRAC)) {
10146 v = (CUR - '0');
10147 fraction = fraction * 10 + v;
10148 frac = frac + 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010149 NEXT;
10150 }
Phil Shaferee32ad32010-11-03 20:53:55 +010010151 fraction /= my_pow10[frac];
10152 ret = ret + fraction;
10153 while ((CUR >= '0') && (CUR <= '9'))
10154 NEXT;
Owen Taylor3473f882001-02-23 17:55:21 +000010155 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010156 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010157 NEXT;
10158 if (CUR == '-') {
10159 is_exponent_negative = 1;
10160 NEXT;
William M. Brack99127052004-05-24 02:52:28 +000010161 } else if (CUR == '+') {
10162 NEXT;
10163 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010164 while ((CUR >= '0') && (CUR <= '9')) {
10165 exponent = exponent * 10 + (CUR - '0');
10166 NEXT;
10167 }
10168 if (is_exponent_negative)
10169 exponent = -exponent;
10170 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +000010171 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010172 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010173 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010174}
10175
10176/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010177 * xmlXPathParseLiteral:
10178 * @ctxt: the XPath Parser context
10179 *
10180 * Parse a Literal
10181 *
10182 * [29] Literal ::= '"' [^"]* '"'
10183 * | "'" [^']* "'"
10184 *
10185 * Returns the value found or NULL in case of error
10186 */
10187static xmlChar *
10188xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10189 const xmlChar *q;
10190 xmlChar *ret = NULL;
10191
10192 if (CUR == '"') {
10193 NEXT;
10194 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010195 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010196 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010197 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010198 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010199 } else {
10200 ret = xmlStrndup(q, CUR_PTR - q);
10201 NEXT;
10202 }
10203 } else if (CUR == '\'') {
10204 NEXT;
10205 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010206 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010207 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010208 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010209 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010210 } else {
10211 ret = xmlStrndup(q, CUR_PTR - q);
10212 NEXT;
10213 }
10214 } else {
Daniel Veillard24505b02005-07-28 23:49:35 +000010215 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010216 }
10217 return(ret);
10218}
10219
10220/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010221 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +000010222 * @ctxt: the XPath Parser context
10223 *
10224 * Parse a Literal and push it on the stack.
10225 *
10226 * [29] Literal ::= '"' [^"]* '"'
10227 * | "'" [^']* "'"
10228 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010229 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +000010230 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010231static void
10232xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010233 const xmlChar *q;
10234 xmlChar *ret = NULL;
10235
10236 if (CUR == '"') {
10237 NEXT;
10238 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010239 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +000010240 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010241 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010242 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10243 } else {
10244 ret = xmlStrndup(q, CUR_PTR - q);
10245 NEXT;
10246 }
10247 } else if (CUR == '\'') {
10248 NEXT;
10249 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010250 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +000010251 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010252 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010253 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10254 } else {
10255 ret = xmlStrndup(q, CUR_PTR - q);
10256 NEXT;
10257 }
10258 } else {
10259 XP_ERROR(XPATH_START_LITERAL_ERROR);
10260 }
10261 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010262 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010263 xmlXPathCacheNewString(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010264 xmlFree(ret);
10265}
10266
10267/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010268 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +000010269 * @ctxt: the XPath Parser context
10270 *
10271 * Parse a VariableReference, evaluate it and push it on the stack.
10272 *
10273 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +000010274 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +000010275 * of any of the types that are possible for the value of an expression,
10276 * and may also be of additional types not specified here.
10277 *
10278 * Early evaluation is possible since:
10279 * The variable bindings [...] used to evaluate a subexpression are
Daniel Veillard45490ae2008-07-29 09:13:19 +000010280 * always the same as those used to evaluate the containing expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010281 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010282 * [36] VariableReference ::= '$' QName
Owen Taylor3473f882001-02-23 17:55:21 +000010283 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010284static void
10285xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010286 xmlChar *name;
10287 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010288
10289 SKIP_BLANKS;
10290 if (CUR != '$') {
10291 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10292 }
10293 NEXT;
10294 name = xmlXPathParseQName(ctxt, &prefix);
10295 if (name == NULL) {
10296 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10297 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010298 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010299 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10300 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010301 SKIP_BLANKS;
Daniel Veillardb3d14912005-09-04 20:47:39 +000010302 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10303 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
10304 }
Owen Taylor3473f882001-02-23 17:55:21 +000010305}
10306
10307/**
10308 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +000010309 * @name: a name string
10310 *
10311 * Is the name given a NodeType one.
10312 *
10313 * [38] NodeType ::= 'comment'
10314 * | 'text'
10315 * | 'processing-instruction'
10316 * | 'node'
10317 *
10318 * Returns 1 if true 0 otherwise
10319 */
10320int
10321xmlXPathIsNodeType(const xmlChar *name) {
10322 if (name == NULL)
10323 return(0);
10324
Daniel Veillard1971ee22002-01-31 20:29:19 +000010325 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +000010326 return(1);
10327 if (xmlStrEqual(name, BAD_CAST "text"))
10328 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010329 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +000010330 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010331 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +000010332 return(1);
10333 return(0);
10334}
10335
10336/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010337 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +000010338 * @ctxt: the XPath Parser context
10339 *
10340 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010341 * [17] Argument ::= Expr
Owen Taylor3473f882001-02-23 17:55:21 +000010342 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010343 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +000010344 * pushed on the stack
10345 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010346static void
10347xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010348 xmlChar *name;
10349 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010350 int nbargs = 0;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010351 int sort = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010352
10353 name = xmlXPathParseQName(ctxt, &prefix);
10354 if (name == NULL) {
Daniel Veillard074f37e2008-09-01 13:38:22 +000010355 xmlFree(prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010356 XP_ERROR(XPATH_EXPR_ERROR);
10357 }
10358 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010359#ifdef DEBUG_EXPR
10360 if (prefix == NULL)
10361 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10362 name);
10363 else
10364 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10365 prefix, name);
10366#endif
10367
Owen Taylor3473f882001-02-23 17:55:21 +000010368 if (CUR != '(') {
10369 XP_ERROR(XPATH_EXPR_ERROR);
10370 }
10371 NEXT;
10372 SKIP_BLANKS;
10373
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010374 /*
10375 * Optimization for count(): we don't need the node-set to be sorted.
10376 */
10377 if ((prefix == NULL) && (name[0] == 'c') &&
10378 xmlStrEqual(name, BAD_CAST "count"))
10379 {
10380 sort = 0;
10381 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010382 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +000010383 if (CUR != ')') {
10384 while (CUR != 0) {
10385 int op1 = ctxt->comp->last;
10386 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010387 xmlXPathCompileExpr(ctxt, sort);
Daniel Veillard074f37e2008-09-01 13:38:22 +000010388 if (ctxt->error != XPATH_EXPRESSION_OK) {
10389 xmlFree(name);
10390 xmlFree(prefix);
10391 return;
10392 }
Daniel Veillard71f9d732003-01-14 16:07:16 +000010393 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10394 nbargs++;
10395 if (CUR == ')') break;
10396 if (CUR != ',') {
10397 XP_ERROR(XPATH_EXPR_ERROR);
10398 }
10399 NEXT;
10400 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010401 }
Owen Taylor3473f882001-02-23 17:55:21 +000010402 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010403 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10404 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010405 NEXT;
10406 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010407}
10408
10409/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010410 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010411 * @ctxt: the XPath Parser context
10412 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010413 * [15] PrimaryExpr ::= VariableReference
Owen Taylor3473f882001-02-23 17:55:21 +000010414 * | '(' Expr ')'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010415 * | Literal
10416 * | Number
10417 * | FunctionCall
Owen Taylor3473f882001-02-23 17:55:21 +000010418 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010419 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010420 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010421static void
10422xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010423 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010424 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010425 else if (CUR == '(') {
10426 NEXT;
10427 SKIP_BLANKS;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010428 xmlXPathCompileExpr(ctxt, 1);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010429 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000010430 if (CUR != ')') {
10431 XP_ERROR(XPATH_EXPR_ERROR);
10432 }
10433 NEXT;
10434 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010435 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010436 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010437 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010438 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010439 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010440 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010441 }
10442 SKIP_BLANKS;
10443}
10444
10445/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010446 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010447 * @ctxt: the XPath Parser context
10448 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010449 * [20] FilterExpr ::= PrimaryExpr
10450 * | FilterExpr Predicate
Owen Taylor3473f882001-02-23 17:55:21 +000010451 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010452 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010453 * Square brackets are used to filter expressions in the same way that
10454 * they are used in location paths. It is an error if the expression to
10455 * be filtered does not evaluate to a node-set. The context node list
10456 * used for evaluating the expression in square brackets is the node-set
10457 * to be filtered listed in document order.
10458 */
10459
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010460static void
10461xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10462 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010463 CHECK_ERROR;
10464 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010465
Owen Taylor3473f882001-02-23 17:55:21 +000010466 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010467 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +000010468 SKIP_BLANKS;
10469 }
10470
Daniel Veillard45490ae2008-07-29 09:13:19 +000010471
Owen Taylor3473f882001-02-23 17:55:21 +000010472}
10473
10474/**
10475 * xmlXPathScanName:
10476 * @ctxt: the XPath Parser context
10477 *
10478 * Trickery: parse an XML name but without consuming the input flow
10479 * Needed to avoid insanity in the parser state.
10480 *
10481 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10482 * CombiningChar | Extender
10483 *
10484 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10485 *
10486 * [6] Names ::= Name (S Name)*
10487 *
10488 * Returns the Name parsed or NULL
10489 */
10490
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010491static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +000010492xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +000010493 int len = 0, l;
10494 int c;
Daniel Veillard03226812004-11-01 14:55:21 +000010495 const xmlChar *cur;
10496 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +000010497
Daniel Veillard03226812004-11-01 14:55:21 +000010498 cur = ctxt->cur;
10499
10500 c = CUR_CHAR(l);
10501 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10502 (!IS_LETTER(c) && (c != '_') &&
10503 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010504 return(NULL);
10505 }
10506
Daniel Veillard03226812004-11-01 14:55:21 +000010507 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10508 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10509 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000010510 (c == '_') || (c == ':') ||
Daniel Veillard03226812004-11-01 14:55:21 +000010511 (IS_COMBINING(c)) ||
10512 (IS_EXTENDER(c)))) {
10513 len += l;
10514 NEXTL(l);
10515 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +000010516 }
Daniel Veillard03226812004-11-01 14:55:21 +000010517 ret = xmlStrndup(cur, ctxt->cur - cur);
10518 ctxt->cur = cur;
10519 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +000010520}
10521
10522/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010523 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010524 * @ctxt: the XPath Parser context
10525 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010526 * [19] PathExpr ::= LocationPath
10527 * | FilterExpr
10528 * | FilterExpr '/' RelativeLocationPath
10529 * | FilterExpr '//' RelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000010530 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010531 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010532 * The / operator and // operators combine an arbitrary expression
10533 * and a relative location path. It is an error if the expression
10534 * does not evaluate to a node-set.
10535 * The / operator does composition in the same way as when / is
10536 * used in a location path. As in location paths, // is short for
10537 * /descendant-or-self::node()/.
10538 */
10539
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010540static void
10541xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010542 int lc = 1; /* Should we branch to LocationPath ? */
10543 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10544
10545 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010546 if ((CUR == '$') || (CUR == '(') ||
10547 (IS_ASCII_DIGIT(CUR)) ||
William M. Brackd1757ab2004-10-02 22:07:48 +000010548 (CUR == '\'') || (CUR == '"') ||
10549 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010550 lc = 0;
10551 } else if (CUR == '*') {
10552 /* relative or absolute location path */
10553 lc = 1;
10554 } else if (CUR == '/') {
10555 /* relative or absolute location path */
10556 lc = 1;
10557 } else if (CUR == '@') {
10558 /* relative abbreviated attribute location path */
10559 lc = 1;
10560 } else if (CUR == '.') {
10561 /* relative abbreviated attribute location path */
10562 lc = 1;
10563 } else {
10564 /*
10565 * Problem is finding if we have a name here whether it's:
10566 * - a nodetype
10567 * - a function call in which case it's followed by '('
10568 * - an axis in which case it's followed by ':'
10569 * - a element name
10570 * We do an a priori analysis here rather than having to
10571 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +000010572 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +000010573 * read/write/debug.
10574 */
10575 SKIP_BLANKS;
10576 name = xmlXPathScanName(ctxt);
10577 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10578#ifdef DEBUG_STEP
10579 xmlGenericError(xmlGenericErrorContext,
10580 "PathExpr: Axis\n");
10581#endif
10582 lc = 1;
10583 xmlFree(name);
10584 } else if (name != NULL) {
10585 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +000010586
Daniel Veillard45490ae2008-07-29 09:13:19 +000010587
Owen Taylor3473f882001-02-23 17:55:21 +000010588 while (NXT(len) != 0) {
10589 if (NXT(len) == '/') {
10590 /* element name */
10591#ifdef DEBUG_STEP
10592 xmlGenericError(xmlGenericErrorContext,
10593 "PathExpr: AbbrRelLocation\n");
10594#endif
10595 lc = 1;
10596 break;
William M. Brack76e95df2003-10-18 16:20:14 +000010597 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +000010598 /* ignore blanks */
10599 ;
Owen Taylor3473f882001-02-23 17:55:21 +000010600 } else if (NXT(len) == ':') {
10601#ifdef DEBUG_STEP
10602 xmlGenericError(xmlGenericErrorContext,
10603 "PathExpr: AbbrRelLocation\n");
10604#endif
10605 lc = 1;
10606 break;
10607 } else if ((NXT(len) == '(')) {
10608 /* Note Type or Function */
10609 if (xmlXPathIsNodeType(name)) {
10610#ifdef DEBUG_STEP
10611 xmlGenericError(xmlGenericErrorContext,
10612 "PathExpr: Type search\n");
10613#endif
10614 lc = 1;
10615 } else {
10616#ifdef DEBUG_STEP
10617 xmlGenericError(xmlGenericErrorContext,
10618 "PathExpr: function call\n");
10619#endif
10620 lc = 0;
10621 }
10622 break;
10623 } else if ((NXT(len) == '[')) {
10624 /* element name */
10625#ifdef DEBUG_STEP
10626 xmlGenericError(xmlGenericErrorContext,
10627 "PathExpr: AbbrRelLocation\n");
10628#endif
10629 lc = 1;
10630 break;
10631 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10632 (NXT(len) == '=')) {
10633 lc = 1;
10634 break;
10635 } else {
10636 lc = 1;
10637 break;
10638 }
10639 len++;
10640 }
10641 if (NXT(len) == 0) {
10642#ifdef DEBUG_STEP
10643 xmlGenericError(xmlGenericErrorContext,
10644 "PathExpr: AbbrRelLocation\n");
10645#endif
10646 /* element name */
10647 lc = 1;
10648 }
10649 xmlFree(name);
10650 } else {
William M. Brack08171912003-12-29 02:52:11 +000010651 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +000010652 XP_ERROR(XPATH_EXPR_ERROR);
10653 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000010654 }
Owen Taylor3473f882001-02-23 17:55:21 +000010655
10656 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010657 if (CUR == '/') {
10658 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10659 } else {
10660 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010661 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010662 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010663 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010664 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010665 CHECK_ERROR;
10666 if ((CUR == '/') && (NXT(1) == '/')) {
10667 SKIP(2);
10668 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010669
10670 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10671 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10672 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10673
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010674 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010675 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010676 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010677 }
10678 }
10679 SKIP_BLANKS;
10680}
10681
10682/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010683 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010684 * @ctxt: the XPath Parser context
10685 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010686 * [18] UnionExpr ::= PathExpr
10687 * | UnionExpr '|' PathExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010688 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010689 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010690 */
10691
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010692static void
10693xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10694 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010695 CHECK_ERROR;
10696 SKIP_BLANKS;
10697 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010698 int op1 = ctxt->comp->last;
10699 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010700
10701 NEXT;
10702 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010703 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010704
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010705 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10706
Owen Taylor3473f882001-02-23 17:55:21 +000010707 SKIP_BLANKS;
10708 }
Owen Taylor3473f882001-02-23 17:55:21 +000010709}
10710
10711/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010712 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010713 * @ctxt: the XPath Parser context
10714 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010715 * [27] UnaryExpr ::= UnionExpr
10716 * | '-' UnaryExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010717 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010718 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010719 */
10720
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010721static void
10722xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010723 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010724 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010725
10726 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +000010727 while (CUR == '-') {
10728 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010729 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010730 NEXT;
10731 SKIP_BLANKS;
10732 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010733
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010734 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010735 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010736 if (found) {
10737 if (minus)
10738 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10739 else
10740 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010741 }
10742}
10743
10744/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010745 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010746 * @ctxt: the XPath Parser context
10747 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010748 * [26] MultiplicativeExpr ::= UnaryExpr
10749 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10750 * | MultiplicativeExpr 'div' UnaryExpr
10751 * | MultiplicativeExpr 'mod' UnaryExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010752 * [34] MultiplyOperator ::= '*'
10753 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010754 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010755 */
10756
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010757static void
10758xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10759 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010760 CHECK_ERROR;
10761 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010762 while ((CUR == '*') ||
Owen Taylor3473f882001-02-23 17:55:21 +000010763 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10764 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10765 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010766 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010767
10768 if (CUR == '*') {
10769 op = 0;
10770 NEXT;
10771 } else if (CUR == 'd') {
10772 op = 1;
10773 SKIP(3);
10774 } else if (CUR == 'm') {
10775 op = 2;
10776 SKIP(3);
10777 }
10778 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010779 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010780 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010781 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010782 SKIP_BLANKS;
10783 }
10784}
10785
10786/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010787 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010788 * @ctxt: the XPath Parser context
10789 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010790 * [25] AdditiveExpr ::= MultiplicativeExpr
10791 * | AdditiveExpr '+' MultiplicativeExpr
10792 * | AdditiveExpr '-' MultiplicativeExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010793 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010794 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010795 */
10796
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010797static void
10798xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010799
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010800 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010801 CHECK_ERROR;
10802 SKIP_BLANKS;
10803 while ((CUR == '+') || (CUR == '-')) {
10804 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010805 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010806
10807 if (CUR == '+') plus = 1;
10808 else plus = 0;
10809 NEXT;
10810 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010811 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010812 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010813 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010814 SKIP_BLANKS;
10815 }
10816}
10817
10818/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010819 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010820 * @ctxt: the XPath Parser context
10821 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010822 * [24] RelationalExpr ::= AdditiveExpr
10823 * | RelationalExpr '<' AdditiveExpr
10824 * | RelationalExpr '>' AdditiveExpr
10825 * | RelationalExpr '<=' AdditiveExpr
10826 * | RelationalExpr '>=' AdditiveExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010827 *
10828 * A <= B > C is allowed ? Answer from James, yes with
10829 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10830 * which is basically what got implemented.
10831 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010832 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +000010833 * on the stack
10834 */
10835
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010836static void
10837xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10838 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010839 CHECK_ERROR;
10840 SKIP_BLANKS;
10841 while ((CUR == '<') ||
10842 (CUR == '>') ||
10843 ((CUR == '<') && (NXT(1) == '=')) ||
10844 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010845 int inf, strict;
10846 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010847
10848 if (CUR == '<') inf = 1;
10849 else inf = 0;
10850 if (NXT(1) == '=') strict = 0;
10851 else strict = 1;
10852 NEXT;
10853 if (!strict) NEXT;
10854 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010855 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010856 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010857 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +000010858 SKIP_BLANKS;
10859 }
10860}
10861
10862/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010863 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010864 * @ctxt: the XPath Parser context
10865 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010866 * [23] EqualityExpr ::= RelationalExpr
10867 * | EqualityExpr '=' RelationalExpr
10868 * | EqualityExpr '!=' RelationalExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010869 *
10870 * A != B != C is allowed ? Answer from James, yes with
10871 * (RelationalExpr = RelationalExpr) = RelationalExpr
10872 * (RelationalExpr != RelationalExpr) != RelationalExpr
10873 * which is basically what got implemented.
10874 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010875 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010876 *
10877 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010878static void
10879xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10880 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010881 CHECK_ERROR;
10882 SKIP_BLANKS;
10883 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010884 int eq;
10885 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010886
10887 if (CUR == '=') eq = 1;
10888 else eq = 0;
10889 NEXT;
10890 if (!eq) NEXT;
10891 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010892 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010893 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010894 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010895 SKIP_BLANKS;
10896 }
10897}
10898
10899/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010900 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010901 * @ctxt: the XPath Parser context
10902 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010903 * [22] AndExpr ::= EqualityExpr
10904 * | AndExpr 'and' EqualityExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010905 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010906 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010907 *
10908 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010909static void
10910xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10911 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010912 CHECK_ERROR;
10913 SKIP_BLANKS;
10914 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010915 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010916 SKIP(3);
10917 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010918 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010919 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010920 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010921 SKIP_BLANKS;
10922 }
10923}
10924
10925/**
Daniel Veillard591b4be2003-02-09 23:33:36 +000010926 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010927 * @ctxt: the XPath Parser context
10928 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010929 * [14] Expr ::= OrExpr
10930 * [21] OrExpr ::= AndExpr
10931 * | OrExpr 'or' AndExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010932 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010933 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +000010934 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010935static void
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010936xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010937 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010938 CHECK_ERROR;
10939 SKIP_BLANKS;
10940 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010941 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010942 SKIP(2);
10943 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010944 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010945 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010946 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010947 SKIP_BLANKS;
10948 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010949 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010950 /* more ops could be optimized too */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010951 /*
10952 * This is the main place to eliminate sorting for
10953 * operations which don't require a sorted node-set.
10954 * E.g. count().
10955 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010956 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10957 }
Owen Taylor3473f882001-02-23 17:55:21 +000010958}
10959
10960/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010961 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +000010962 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010963 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +000010964 *
10965 * [8] Predicate ::= '[' PredicateExpr ']'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010966 * [9] PredicateExpr ::= Expr
Owen Taylor3473f882001-02-23 17:55:21 +000010967 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010968 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +000010969 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010970static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010971xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010972 int op1 = ctxt->comp->last;
10973
10974 SKIP_BLANKS;
10975 if (CUR != '[') {
10976 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10977 }
10978 NEXT;
10979 SKIP_BLANKS;
10980
10981 ctxt->comp->last = -1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000010982 /*
10983 * This call to xmlXPathCompileExpr() will deactivate sorting
10984 * of the predicate result.
10985 * TODO: Sorting is still activated for filters, since I'm not
10986 * sure if needed. Normally sorting should not be needed, since
10987 * a filter can only diminish the number of items in a sequence,
10988 * but won't change its order; so if the initial sequence is sorted,
10989 * subsequent sorting is not needed.
10990 */
10991 if (! filter)
10992 xmlXPathCompileExpr(ctxt, 0);
10993 else
10994 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010995 CHECK_ERROR;
10996
10997 if (CUR != ']') {
10998 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10999 }
11000
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011001 if (filter)
11002 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11003 else
11004 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011005
11006 NEXT;
11007 SKIP_BLANKS;
11008}
11009
11010/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011011 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +000011012 * @ctxt: the XPath Parser context
11013 * @test: pointer to a xmlXPathTestVal
11014 * @type: pointer to a xmlXPathTypeVal
11015 * @prefix: placeholder for a possible name prefix
11016 *
11017 * [7] NodeTest ::= NameTest
11018 * | NodeType '(' ')'
11019 * | 'processing-instruction' '(' Literal ')'
11020 *
11021 * [37] NameTest ::= '*'
11022 * | NCName ':' '*'
11023 * | QName
11024 * [38] NodeType ::= 'comment'
11025 * | 'text'
11026 * | 'processing-instruction'
11027 * | 'node'
11028 *
William M. Brack08171912003-12-29 02:52:11 +000011029 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +000011030 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011031static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011032xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11033 xmlXPathTypeVal *type, const xmlChar **prefix,
11034 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +000011035 int blanks;
11036
11037 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11038 STRANGE;
11039 return(NULL);
11040 }
William M. Brack78637da2003-07-31 14:47:38 +000011041 *type = (xmlXPathTypeVal) 0;
11042 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011043 *prefix = NULL;
11044 SKIP_BLANKS;
11045
11046 if ((name == NULL) && (CUR == '*')) {
11047 /*
11048 * All elements
11049 */
11050 NEXT;
11051 *test = NODE_TEST_ALL;
11052 return(NULL);
11053 }
11054
11055 if (name == NULL)
11056 name = xmlXPathParseNCName(ctxt);
11057 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011058 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011059 }
11060
William M. Brack76e95df2003-10-18 16:20:14 +000011061 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +000011062 SKIP_BLANKS;
11063 if (CUR == '(') {
11064 NEXT;
11065 /*
11066 * NodeType or PI search
11067 */
11068 if (xmlStrEqual(name, BAD_CAST "comment"))
11069 *type = NODE_TYPE_COMMENT;
11070 else if (xmlStrEqual(name, BAD_CAST "node"))
11071 *type = NODE_TYPE_NODE;
11072 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11073 *type = NODE_TYPE_PI;
11074 else if (xmlStrEqual(name, BAD_CAST "text"))
11075 *type = NODE_TYPE_TEXT;
11076 else {
11077 if (name != NULL)
11078 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000011079 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011080 }
11081
11082 *test = NODE_TEST_TYPE;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011083
Owen Taylor3473f882001-02-23 17:55:21 +000011084 SKIP_BLANKS;
11085 if (*type == NODE_TYPE_PI) {
11086 /*
11087 * Specific case: search a PI by name.
11088 */
Owen Taylor3473f882001-02-23 17:55:21 +000011089 if (name != NULL)
11090 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +000011091 name = NULL;
11092 if (CUR != ')') {
11093 name = xmlXPathParseLiteral(ctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000011094 CHECK_ERROR NULL;
Daniel Veillarded23b7d2002-05-27 12:16:02 +000011095 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +000011096 SKIP_BLANKS;
11097 }
Owen Taylor3473f882001-02-23 17:55:21 +000011098 }
11099 if (CUR != ')') {
11100 if (name != NULL)
11101 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000011102 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011103 }
11104 NEXT;
11105 return(name);
11106 }
11107 *test = NODE_TEST_NAME;
11108 if ((!blanks) && (CUR == ':')) {
11109 NEXT;
11110
11111 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011112 * Since currently the parser context don't have a
11113 * namespace list associated:
11114 * The namespace name for this prefix can be computed
11115 * only at evaluation time. The compilation is done
11116 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +000011117 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011118#if 0
Owen Taylor3473f882001-02-23 17:55:21 +000011119 *prefix = xmlXPathNsLookup(ctxt->context, name);
11120 if (name != NULL)
11121 xmlFree(name);
11122 if (*prefix == NULL) {
11123 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11124 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011125#else
11126 *prefix = name;
11127#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011128
11129 if (CUR == '*') {
11130 /*
11131 * All elements
11132 */
11133 NEXT;
11134 *test = NODE_TEST_ALL;
11135 return(NULL);
11136 }
11137
11138 name = xmlXPathParseNCName(ctxt);
11139 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011140 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011141 }
11142 }
11143 return(name);
11144}
11145
11146/**
11147 * xmlXPathIsAxisName:
11148 * @name: a preparsed name token
11149 *
11150 * [6] AxisName ::= 'ancestor'
11151 * | 'ancestor-or-self'
11152 * | 'attribute'
11153 * | 'child'
11154 * | 'descendant'
11155 * | 'descendant-or-self'
11156 * | 'following'
11157 * | 'following-sibling'
11158 * | 'namespace'
11159 * | 'parent'
11160 * | 'preceding'
11161 * | 'preceding-sibling'
11162 * | 'self'
11163 *
11164 * Returns the axis or 0
11165 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011166static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +000011167xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +000011168 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011169 switch (name[0]) {
11170 case 'a':
11171 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11172 ret = AXIS_ANCESTOR;
11173 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11174 ret = AXIS_ANCESTOR_OR_SELF;
11175 if (xmlStrEqual(name, BAD_CAST "attribute"))
11176 ret = AXIS_ATTRIBUTE;
11177 break;
11178 case 'c':
11179 if (xmlStrEqual(name, BAD_CAST "child"))
11180 ret = AXIS_CHILD;
11181 break;
11182 case 'd':
11183 if (xmlStrEqual(name, BAD_CAST "descendant"))
11184 ret = AXIS_DESCENDANT;
11185 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11186 ret = AXIS_DESCENDANT_OR_SELF;
11187 break;
11188 case 'f':
11189 if (xmlStrEqual(name, BAD_CAST "following"))
11190 ret = AXIS_FOLLOWING;
11191 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11192 ret = AXIS_FOLLOWING_SIBLING;
11193 break;
11194 case 'n':
11195 if (xmlStrEqual(name, BAD_CAST "namespace"))
11196 ret = AXIS_NAMESPACE;
11197 break;
11198 case 'p':
11199 if (xmlStrEqual(name, BAD_CAST "parent"))
11200 ret = AXIS_PARENT;
11201 if (xmlStrEqual(name, BAD_CAST "preceding"))
11202 ret = AXIS_PRECEDING;
11203 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11204 ret = AXIS_PRECEDING_SIBLING;
11205 break;
11206 case 's':
11207 if (xmlStrEqual(name, BAD_CAST "self"))
11208 ret = AXIS_SELF;
11209 break;
11210 }
11211 return(ret);
11212}
11213
11214/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011215 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +000011216 * @ctxt: the XPath Parser context
11217 *
11218 * [4] Step ::= AxisSpecifier NodeTest Predicate*
Daniel Veillard45490ae2008-07-29 09:13:19 +000011219 * | AbbreviatedStep
Owen Taylor3473f882001-02-23 17:55:21 +000011220 *
11221 * [12] AbbreviatedStep ::= '.' | '..'
11222 *
11223 * [5] AxisSpecifier ::= AxisName '::'
11224 * | AbbreviatedAxisSpecifier
11225 *
11226 * [13] AbbreviatedAxisSpecifier ::= '@'?
11227 *
11228 * Modified for XPtr range support as:
11229 *
11230 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11231 * | AbbreviatedStep
11232 * | 'range-to' '(' Expr ')' Predicate*
11233 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011234 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +000011235 * A location step of . is short for self::node(). This is
11236 * particularly useful in conjunction with //. For example, the
11237 * location path .//para is short for
11238 * self::node()/descendant-or-self::node()/child::para
11239 * and so will select all para descendant elements of the context
11240 * node.
11241 * Similarly, a location step of .. is short for parent::node().
11242 * For example, ../title is short for parent::node()/child::title
11243 * and so will select the title children of the parent of the context
11244 * node.
11245 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011246static void
11247xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011248#ifdef LIBXML_XPTR_ENABLED
11249 int rangeto = 0;
11250 int op2 = -1;
11251#endif
11252
Owen Taylor3473f882001-02-23 17:55:21 +000011253 SKIP_BLANKS;
11254 if ((CUR == '.') && (NXT(1) == '.')) {
11255 SKIP(2);
11256 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011257 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11258 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011259 } else if (CUR == '.') {
11260 NEXT;
11261 SKIP_BLANKS;
11262 } else {
11263 xmlChar *name = NULL;
11264 const xmlChar *prefix = NULL;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011265 xmlXPathTestVal test = (xmlXPathTestVal) 0;
William M. Brack78637da2003-07-31 14:47:38 +000011266 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011267 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011268 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +000011269
11270 /*
11271 * The modification needed for XPointer change to the production
11272 */
11273#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011274 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +000011275 name = xmlXPathParseNCName(ctxt);
11276 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011277 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011278 xmlFree(name);
11279 SKIP_BLANKS;
11280 if (CUR != '(') {
11281 XP_ERROR(XPATH_EXPR_ERROR);
11282 }
11283 NEXT;
11284 SKIP_BLANKS;
11285
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011286 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011287 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +000011288 CHECK_ERROR;
11289
11290 SKIP_BLANKS;
11291 if (CUR != ')') {
11292 XP_ERROR(XPATH_EXPR_ERROR);
11293 }
11294 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011295 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000011296 goto eval_predicates;
11297 }
11298 }
11299#endif
Daniel Veillard2156a562001-04-28 12:24:34 +000011300 if (CUR == '*') {
11301 axis = AXIS_CHILD;
11302 } else {
11303 if (name == NULL)
11304 name = xmlXPathParseNCName(ctxt);
11305 if (name != NULL) {
11306 axis = xmlXPathIsAxisName(name);
11307 if (axis != 0) {
11308 SKIP_BLANKS;
11309 if ((CUR == ':') && (NXT(1) == ':')) {
11310 SKIP(2);
11311 xmlFree(name);
11312 name = NULL;
11313 } else {
11314 /* an element name can conflict with an axis one :-\ */
11315 axis = AXIS_CHILD;
11316 }
Owen Taylor3473f882001-02-23 17:55:21 +000011317 } else {
Owen Taylor3473f882001-02-23 17:55:21 +000011318 axis = AXIS_CHILD;
11319 }
Daniel Veillard2156a562001-04-28 12:24:34 +000011320 } else if (CUR == '@') {
11321 NEXT;
11322 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +000011323 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +000011324 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +000011325 }
Owen Taylor3473f882001-02-23 17:55:21 +000011326 }
11327
Daniel Veillard2f3523f2010-10-15 18:30:29 +020011328 if (ctxt->error != XPATH_EXPRESSION_OK) {
11329 xmlFree(name);
11330 return;
11331 }
Owen Taylor3473f882001-02-23 17:55:21 +000011332
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011333 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +000011334 if (test == 0)
11335 return;
11336
Daniel Veillarded6c5492005-07-23 15:00:22 +000011337 if ((prefix != NULL) && (ctxt->context != NULL) &&
11338 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11339 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11340 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11341 }
11342 }
Owen Taylor3473f882001-02-23 17:55:21 +000011343#ifdef DEBUG_STEP
11344 xmlGenericError(xmlGenericErrorContext,
11345 "Basis : computing new set\n");
11346#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011347
Owen Taylor3473f882001-02-23 17:55:21 +000011348#ifdef DEBUG_STEP
11349 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011350 if (ctxt->value == NULL)
11351 xmlGenericError(xmlGenericErrorContext, "no value\n");
11352 else if (ctxt->value->nodesetval == NULL)
11353 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11354 else
11355 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011356#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011357
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011358#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +000011359eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011360#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011361 op1 = ctxt->comp->last;
11362 ctxt->comp->last = -1;
11363
Owen Taylor3473f882001-02-23 17:55:21 +000011364 SKIP_BLANKS;
11365 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011366 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011367 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011368
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011369#ifdef LIBXML_XPTR_ENABLED
11370 if (rangeto) {
11371 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11372 } else
11373#endif
11374 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11375 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011376
Owen Taylor3473f882001-02-23 17:55:21 +000011377 }
11378#ifdef DEBUG_STEP
11379 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011380 if (ctxt->value == NULL)
11381 xmlGenericError(xmlGenericErrorContext, "no value\n");
11382 else if (ctxt->value->nodesetval == NULL)
11383 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11384 else
11385 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11386 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011387#endif
11388}
11389
11390/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011391 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011392 * @ctxt: the XPath Parser context
11393 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011394 * [3] RelativeLocationPath ::= Step
11395 * | RelativeLocationPath '/' Step
11396 * | AbbreviatedRelativeLocationPath
11397 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
Owen Taylor3473f882001-02-23 17:55:21 +000011398 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011399 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +000011400 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011401static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011402xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011403(xmlXPathParserContextPtr ctxt) {
11404 SKIP_BLANKS;
11405 if ((CUR == '/') && (NXT(1) == '/')) {
11406 SKIP(2);
11407 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011408 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11409 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011410 } else if (CUR == '/') {
11411 NEXT;
11412 SKIP_BLANKS;
11413 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011414 xmlXPathCompStep(ctxt);
Martin729601f2009-10-12 22:42:26 +020011415 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000011416 SKIP_BLANKS;
11417 while (CUR == '/') {
11418 if ((CUR == '/') && (NXT(1) == '/')) {
11419 SKIP(2);
11420 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011421 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +000011422 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011423 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011424 } else if (CUR == '/') {
11425 NEXT;
11426 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011427 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011428 }
11429 SKIP_BLANKS;
11430 }
11431}
11432
11433/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011434 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011435 * @ctxt: the XPath Parser context
11436 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011437 * [1] LocationPath ::= RelativeLocationPath
11438 * | AbsoluteLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011439 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
Daniel Veillard45490ae2008-07-29 09:13:19 +000011440 * | AbbreviatedAbsoluteLocationPath
11441 * [10] AbbreviatedAbsoluteLocationPath ::=
11442 * '//' RelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011443 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011444 * Compile a location path
11445 *
Owen Taylor3473f882001-02-23 17:55:21 +000011446 * // is short for /descendant-or-self::node()/. For example,
11447 * //para is short for /descendant-or-self::node()/child::para and
11448 * so will select any para element in the document (even a para element
11449 * that is a document element will be selected by //para since the
11450 * document element node is a child of the root node); div//para is
11451 * short for div/descendant-or-self::node()/child::para and so will
11452 * select all para descendants of div children.
11453 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011454static void
11455xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000011456 SKIP_BLANKS;
11457 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011458 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011459 } else {
11460 while (CUR == '/') {
11461 if ((CUR == '/') && (NXT(1) == '/')) {
11462 SKIP(2);
11463 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011464 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11465 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011466 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011467 } else if (CUR == '/') {
11468 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +000011469 SKIP_BLANKS;
11470 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +000011471 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +000011472 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011473 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011474 }
Martin729601f2009-10-12 22:42:26 +020011475 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000011476 }
11477 }
11478}
11479
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011480/************************************************************************
11481 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011482 * XPath precompiled expression evaluation *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011483 * *
11484 ************************************************************************/
11485
Daniel Veillardf06307e2001-07-03 10:35:50 +000011486static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011487xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11488
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011489#ifdef DEBUG_STEP
11490static void
Daniel Veillard074f37e2008-09-01 13:38:22 +000011491xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011492 int nbNodes)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011493{
Daniel Veillardf06307e2001-07-03 10:35:50 +000011494 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillard074f37e2008-09-01 13:38:22 +000011495 switch (op->value) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011496 case AXIS_ANCESTOR:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011497 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011498 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011499 case AXIS_ANCESTOR_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011500 xmlGenericError(xmlGenericErrorContext,
11501 "axis 'ancestors-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011502 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011503 case AXIS_ATTRIBUTE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011504 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011505 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011506 case AXIS_CHILD:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011507 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011508 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011509 case AXIS_DESCENDANT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011510 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011511 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011512 case AXIS_DESCENDANT_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011513 xmlGenericError(xmlGenericErrorContext,
11514 "axis 'descendant-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011515 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011516 case AXIS_FOLLOWING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011517 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011518 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011519 case AXIS_FOLLOWING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011520 xmlGenericError(xmlGenericErrorContext,
11521 "axis 'following-siblings' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011522 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011523 case AXIS_NAMESPACE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011524 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011525 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011526 case AXIS_PARENT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011527 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011528 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011529 case AXIS_PRECEDING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011530 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011531 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011532 case AXIS_PRECEDING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011533 xmlGenericError(xmlGenericErrorContext,
11534 "axis 'preceding-sibling' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011535 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011536 case AXIS_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011537 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011538 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011539 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011540 xmlGenericError(xmlGenericErrorContext,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011541 " context contains %d nodes\n", nbNodes);
Daniel Veillard074f37e2008-09-01 13:38:22 +000011542 switch (op->value2) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011543 case NODE_TEST_NONE:
11544 xmlGenericError(xmlGenericErrorContext,
11545 " searching for none !!!\n");
11546 break;
11547 case NODE_TEST_TYPE:
11548 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011549 " searching for type %d\n", op->value3);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011550 break;
11551 case NODE_TEST_PI:
11552 xmlGenericError(xmlGenericErrorContext,
11553 " searching for PI !!!\n");
11554 break;
11555 case NODE_TEST_ALL:
11556 xmlGenericError(xmlGenericErrorContext,
11557 " searching for *\n");
11558 break;
11559 case NODE_TEST_NS:
11560 xmlGenericError(xmlGenericErrorContext,
11561 " searching for namespace %s\n",
Daniel Veillard074f37e2008-09-01 13:38:22 +000011562 op->value5);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011563 break;
11564 case NODE_TEST_NAME:
11565 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011566 " searching for name %s\n", op->value5);
11567 if (op->value4)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011568 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011569 " with namespace %s\n", op->value4);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011570 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011571 }
11572 xmlGenericError(xmlGenericErrorContext, "Testing : ");
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011573}
11574#endif /* DEBUG_STEP */
11575
11576static int
11577xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11578 xmlXPathStepOpPtr op,
11579 xmlNodeSetPtr set,
11580 int contextSize,
11581 int hasNsNodes)
11582{
11583 if (op->ch1 != -1) {
11584 xmlXPathCompExprPtr comp = ctxt->comp;
11585 /*
11586 * Process inner predicates first.
11587 */
11588 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11589 /*
11590 * TODO: raise an internal error.
11591 */
11592 }
11593 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11594 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11595 CHECK_ERROR0;
11596 if (contextSize <= 0)
11597 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011598 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011599 if (op->ch2 != -1) {
11600 xmlXPathContextPtr xpctxt = ctxt->context;
11601 xmlNodePtr contextNode, oldContextNode;
11602 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011603 int i, res, contextPos = 0, newContextSize;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011604 xmlXPathStepOpPtr exprOp;
11605 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11606
11607#ifdef LIBXML_XPTR_ENABLED
11608 /*
11609 * URGENT TODO: Check the following:
11610 * We don't expect location sets if evaluating prediates, right?
11611 * Only filters should expect location sets, right?
11612 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011613#endif
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011614 /*
11615 * SPEC XPath 1.0:
11616 * "For each node in the node-set to be filtered, the
11617 * PredicateExpr is evaluated with that node as the
11618 * context node, with the number of nodes in the
11619 * node-set as the context size, and with the proximity
11620 * position of the node in the node-set with respect to
11621 * the axis as the context position;"
11622 * @oldset is the node-set" to be filtered.
11623 *
11624 * SPEC XPath 1.0:
11625 * "only predicates change the context position and
11626 * context size (see [2.4 Predicates])."
11627 * Example:
11628 * node-set context pos
11629 * nA 1
11630 * nB 2
11631 * nC 3
11632 * After applying predicate [position() > 1] :
11633 * node-set context pos
11634 * nB 1
11635 * nC 2
11636 */
11637 oldContextNode = xpctxt->node;
11638 oldContextDoc = xpctxt->doc;
11639 /*
11640 * Get the expression of this predicate.
11641 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000011642 exprOp = &ctxt->comp->steps[op->ch2];
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011643 newContextSize = 0;
11644 for (i = 0; i < set->nodeNr; i++) {
11645 if (set->nodeTab[i] == NULL)
11646 continue;
11647
11648 contextNode = set->nodeTab[i];
11649 xpctxt->node = contextNode;
11650 xpctxt->contextSize = contextSize;
11651 xpctxt->proximityPosition = ++contextPos;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011652
11653 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011654 * Also set the xpath document in case things like
11655 * key() are evaluated in the predicate.
11656 */
11657 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11658 (contextNode->doc != NULL))
11659 xpctxt->doc = contextNode->doc;
11660 /*
11661 * Evaluate the predicate expression with 1 context node
11662 * at a time; this node is packaged into a node set; this
11663 * node set is handed over to the evaluation mechanism.
11664 */
11665 if (contextObj == NULL)
11666 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11667 else
11668 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11669 contextNode);
11670
11671 valuePush(ctxt, contextObj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011672
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011673 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011674
William M. Brack0bcec062007-02-14 02:15:19 +000011675 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11676 xmlXPathNodeSetClear(set, hasNsNodes);
11677 newContextSize = 0;
11678 goto evaluation_exit;
11679 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011680
11681 if (res != 0) {
11682 newContextSize++;
11683 } else {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011684 /*
11685 * Remove the entry from the initial node set.
11686 */
11687 set->nodeTab[i] = NULL;
11688 if (contextNode->type == XML_NAMESPACE_DECL)
11689 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011690 }
11691 if (ctxt->value == contextObj) {
11692 /*
11693 * Don't free the temporary XPath object holding the
11694 * context node, in order to avoid massive recreation
11695 * inside this loop.
11696 */
11697 valuePop(ctxt);
11698 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11699 } else {
11700 /*
11701 * TODO: The object was lost in the evaluation machinery.
11702 * Can this happen? Maybe in internal-error cases.
11703 */
11704 contextObj = NULL;
11705 }
11706 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011707
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011708 if (contextObj != NULL) {
11709 if (ctxt->value == contextObj)
11710 valuePop(ctxt);
11711 xmlXPathReleaseObject(xpctxt, contextObj);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011712 }
William M. Brack0bcec062007-02-14 02:15:19 +000011713evaluation_exit:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011714 if (exprRes != NULL)
11715 xmlXPathReleaseObject(ctxt->context, exprRes);
11716 /*
11717 * Reset/invalidate the context.
11718 */
11719 xpctxt->node = oldContextNode;
11720 xpctxt->doc = oldContextDoc;
11721 xpctxt->contextSize = -1;
11722 xpctxt->proximityPosition = -1;
11723 return(newContextSize);
11724 }
11725 return(contextSize);
11726}
11727
11728static int
11729xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11730 xmlXPathStepOpPtr op,
11731 xmlNodeSetPtr set,
11732 int contextSize,
11733 int minPos,
11734 int maxPos,
11735 int hasNsNodes)
11736{
11737 if (op->ch1 != -1) {
11738 xmlXPathCompExprPtr comp = ctxt->comp;
11739 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11740 /*
11741 * TODO: raise an internal error.
11742 */
11743 }
11744 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11745 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11746 CHECK_ERROR0;
11747 if (contextSize <= 0)
11748 return(0);
11749 }
11750 /*
11751 * Check if the node set contains a sufficient number of nodes for
11752 * the requested range.
11753 */
11754 if (contextSize < minPos) {
11755 xmlXPathNodeSetClear(set, hasNsNodes);
11756 return(0);
11757 }
11758 if (op->ch2 == -1) {
11759 /*
11760 * TODO: Can this ever happen?
11761 */
11762 return (contextSize);
11763 } else {
11764 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011765 int i, pos = 0, newContextSize = 0, contextPos = 0, res;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011766 xmlXPathStepOpPtr exprOp;
11767 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11768 xmlNodePtr oldContextNode, contextNode = NULL;
11769 xmlXPathContextPtr xpctxt = ctxt->context;
Daniel Veillardf5048b32011-08-18 17:10:13 +080011770 int frame;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011771
11772#ifdef LIBXML_XPTR_ENABLED
11773 /*
11774 * URGENT TODO: Check the following:
11775 * We don't expect location sets if evaluating prediates, right?
11776 * Only filters should expect location sets, right?
11777 */
11778#endif /* LIBXML_XPTR_ENABLED */
11779
11780 /*
11781 * Save old context.
11782 */
11783 oldContextNode = xpctxt->node;
11784 oldContextDoc = xpctxt->doc;
11785 /*
11786 * Get the expression of this predicate.
11787 */
11788 exprOp = &ctxt->comp->steps[op->ch2];
11789 for (i = 0; i < set->nodeNr; i++) {
Daniel Veillardf5048b32011-08-18 17:10:13 +080011790 xmlXPathObjectPtr tmp;
11791
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011792 if (set->nodeTab[i] == NULL)
11793 continue;
11794
11795 contextNode = set->nodeTab[i];
11796 xpctxt->node = contextNode;
11797 xpctxt->contextSize = contextSize;
11798 xpctxt->proximityPosition = ++contextPos;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011799
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011800 /*
11801 * Initialize the new set.
11802 * Also set the xpath document in case things like
11803 * key() evaluation are attempted on the predicate
11804 */
11805 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11806 (contextNode->doc != NULL))
11807 xpctxt->doc = contextNode->doc;
11808 /*
11809 * Evaluate the predicate expression with 1 context node
11810 * at a time; this node is packaged into a node set; this
11811 * node set is handed over to the evaluation mechanism.
11812 */
11813 if (contextObj == NULL)
11814 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11815 else
11816 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11817 contextNode);
11818
Daniel Veillardf5048b32011-08-18 17:10:13 +080011819 frame = xmlXPathSetFrame(ctxt);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011820 valuePush(ctxt, contextObj);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011821 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Daniel Veillardf5048b32011-08-18 17:10:13 +080011822 tmp = valuePop(ctxt);
11823 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011824
William M. Brackf1794562007-08-23 12:58:13 +000011825 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
Daniel Veillardf5048b32011-08-18 17:10:13 +080011826 while (tmp != contextObj) {
Daniel Veillarddf83c172010-11-17 14:12:14 +010011827 /*
11828 * Free up the result
11829 * then pop off contextObj, which will be freed later
11830 */
11831 xmlXPathReleaseObject(xpctxt, tmp);
Daniel Veillardf5048b32011-08-18 17:10:13 +080011832 tmp = valuePop(ctxt);
Daniel Veillardfec31bc2010-11-18 11:07:24 +010011833 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011834 goto evaluation_error;
William M. Brackf1794562007-08-23 12:58:13 +000011835 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080011836 /* push the result back onto the stack */
11837 valuePush(ctxt, tmp);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011838
11839 if (res)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011840 pos++;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011841
11842 if (res && (pos >= minPos) && (pos <= maxPos)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011843 /*
11844 * Fits in the requested range.
11845 */
11846 newContextSize++;
11847 if (minPos == maxPos) {
11848 /*
11849 * Only 1 node was requested.
11850 */
11851 if (contextNode->type == XML_NAMESPACE_DECL) {
11852 /*
11853 * As always: take care of those nasty
11854 * namespace nodes.
11855 */
11856 set->nodeTab[i] = NULL;
11857 }
11858 xmlXPathNodeSetClear(set, hasNsNodes);
11859 set->nodeNr = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011860 set->nodeTab[0] = contextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011861 goto evaluation_exit;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011862 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011863 if (pos == maxPos) {
11864 /*
11865 * We are done.
11866 */
11867 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11868 goto evaluation_exit;
11869 }
11870 } else {
11871 /*
11872 * Remove the entry from the initial node set.
11873 */
11874 set->nodeTab[i] = NULL;
11875 if (contextNode->type == XML_NAMESPACE_DECL)
11876 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11877 }
11878 if (exprRes != NULL) {
11879 xmlXPathReleaseObject(ctxt->context, exprRes);
11880 exprRes = NULL;
11881 }
11882 if (ctxt->value == contextObj) {
11883 /*
11884 * Don't free the temporary XPath object holding the
11885 * context node, in order to avoid massive recreation
11886 * inside this loop.
11887 */
11888 valuePop(ctxt);
11889 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11890 } else {
11891 /*
11892 * The object was lost in the evaluation machinery.
11893 * Can this happen? Maybe in case of internal-errors.
11894 */
11895 contextObj = NULL;
11896 }
11897 }
11898 goto evaluation_exit;
11899
11900evaluation_error:
11901 xmlXPathNodeSetClear(set, hasNsNodes);
11902 newContextSize = 0;
11903
11904evaluation_exit:
11905 if (contextObj != NULL) {
11906 if (ctxt->value == contextObj)
11907 valuePop(ctxt);
11908 xmlXPathReleaseObject(xpctxt, contextObj);
11909 }
11910 if (exprRes != NULL)
11911 xmlXPathReleaseObject(ctxt->context, exprRes);
11912 /*
11913 * Reset/invalidate the context.
11914 */
11915 xpctxt->node = oldContextNode;
11916 xpctxt->doc = oldContextDoc;
11917 xpctxt->contextSize = -1;
11918 xpctxt->proximityPosition = -1;
11919 return(newContextSize);
11920 }
11921 return(contextSize);
11922}
11923
11924static int
11925xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
Daniel Veillard45490ae2008-07-29 09:13:19 +000011926 xmlXPathStepOpPtr op,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011927 int *maxPos)
11928{
11929
11930 xmlXPathStepOpPtr exprOp;
11931
11932 /*
11933 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11934 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000011935
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011936 /*
11937 * If not -1, then ch1 will point to:
11938 * 1) For predicates (XPATH_OP_PREDICATE):
11939 * - an inner predicate operator
11940 * 2) For filters (XPATH_OP_FILTER):
11941 * - an inner filter operater OR
11942 * - an expression selecting the node set.
11943 * E.g. "key('a', 'b')" or "(//foo | //bar)".
Daniel Veillard45490ae2008-07-29 09:13:19 +000011944 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011945 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11946 return(0);
11947
11948 if (op->ch2 != -1) {
11949 exprOp = &ctxt->comp->steps[op->ch2];
Daniel Veillard45490ae2008-07-29 09:13:19 +000011950 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011951 return(0);
11952
11953 if ((exprOp != NULL) &&
11954 (exprOp->op == XPATH_OP_VALUE) &&
11955 (exprOp->value4 != NULL) &&
11956 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11957 {
11958 /*
11959 * We have a "[n]" predicate here.
11960 * TODO: Unfortunately this simplistic test here is not
11961 * able to detect a position() predicate in compound
11962 * expressions like "[@attr = 'a" and position() = 1],
11963 * and even not the usage of position() in
11964 * "[position() = 1]"; thus - obviously - a position-range,
11965 * like it "[position() < 5]", is also not detected.
11966 * Maybe we could rewrite the AST to ease the optimization.
11967 */
11968 *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011969
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011970 if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
11971 (float) *maxPos)
Daniel Veillard45490ae2008-07-29 09:13:19 +000011972 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011973 return(1);
11974 }
11975 }
11976 return(0);
11977}
11978
11979static int
11980xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11981 xmlXPathStepOpPtr op,
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011982 xmlNodePtr * first, xmlNodePtr * last,
11983 int toBool)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011984{
11985
11986#define XP_TEST_HIT \
11987 if (hasAxisRange != 0) { \
11988 if (++pos == maxPos) { \
11989 addNode(seq, cur); \
11990 goto axis_range_end; } \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011991 } else { \
11992 addNode(seq, cur); \
11993 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011994
11995#define XP_TEST_HIT_NS \
11996 if (hasAxisRange != 0) { \
11997 if (++pos == maxPos) { \
11998 hasNsNodes = 1; \
11999 xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
12000 goto axis_range_end; } \
12001 } else { \
12002 hasNsNodes = 1; \
12003 xmlXPathNodeSetAddNs(seq, \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012004 xpctxt->node, (xmlNsPtr) cur); \
12005 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012006
12007 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
12008 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12009 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12010 const xmlChar *prefix = op->value4;
12011 const xmlChar *name = op->value5;
12012 const xmlChar *URI = NULL;
12013
12014#ifdef DEBUG_STEP
12015 int nbMatches = 0, prevMatches = 0;
12016#endif
12017 int total = 0, hasNsNodes = 0;
12018 /* The popped object holding the context nodes */
12019 xmlXPathObjectPtr obj;
12020 /* The set of context nodes for the node tests */
12021 xmlNodeSetPtr contextSeq;
12022 int contextIdx;
12023 xmlNodePtr contextNode;
12024 /* The context node for a compound traversal */
12025 xmlNodePtr outerContextNode;
12026 /* The final resulting node set wrt to all context nodes */
12027 xmlNodeSetPtr outSeq;
12028 /*
12029 * The temporary resulting node set wrt 1 context node.
12030 * Used to feed predicate evaluation.
12031 */
12032 xmlNodeSetPtr seq;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012033 xmlNodePtr cur;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012034 /* First predicate operator */
12035 xmlXPathStepOpPtr predOp;
12036 int maxPos; /* The requested position() (when a "[n]" predicate) */
12037 int hasPredicateRange, hasAxisRange, pos, size, newSize;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012038 int breakOnFirstHit;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012039
12040 xmlXPathTraversalFunction next = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012041 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12042 xmlXPathNodeSetMergeFunction mergeAndClear;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012043 xmlNodePtr oldContextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012044 xmlXPathContextPtr xpctxt = ctxt->context;
12045
12046
12047 CHECK_TYPE0(XPATH_NODESET);
12048 obj = valuePop(ctxt);
12049 /*
12050 * Setup namespaces.
12051 */
12052 if (prefix != NULL) {
12053 URI = xmlXPathNsLookup(xpctxt, prefix);
12054 if (URI == NULL) {
12055 xmlXPathReleaseObject(xpctxt, obj);
12056 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12057 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012058 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012059 /*
12060 * Setup axis.
12061 *
12062 * MAYBE FUTURE TODO: merging optimizations:
12063 * - If the nodes to be traversed wrt to the initial nodes and
12064 * the current axis cannot overlap, then we could avoid searching
12065 * for duplicates during the merge.
12066 * But the question is how/when to evaluate if they cannot overlap.
12067 * Example: if we know that for two initial nodes, the one is
12068 * not in the ancestor-or-self axis of the other, then we could safely
12069 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12070 * the descendant-or-self axis.
12071 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012072 mergeAndClear = xmlXPathNodeSetMergeAndClear;
12073 switch (axis) {
12074 case AXIS_ANCESTOR:
12075 first = NULL;
12076 next = xmlXPathNextAncestor;
12077 break;
12078 case AXIS_ANCESTOR_OR_SELF:
12079 first = NULL;
12080 next = xmlXPathNextAncestorOrSelf;
12081 break;
12082 case AXIS_ATTRIBUTE:
12083 first = NULL;
12084 last = NULL;
12085 next = xmlXPathNextAttribute;
12086 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12087 break;
12088 case AXIS_CHILD:
12089 last = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012090 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12091 (type == NODE_TYPE_NODE))
12092 {
12093 /*
12094 * Optimization if an element node type is 'element'.
12095 */
12096 next = xmlXPathNextChildElement;
12097 } else
12098 next = xmlXPathNextChild;
12099 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12100 break;
12101 case AXIS_DESCENDANT:
12102 last = NULL;
12103 next = xmlXPathNextDescendant;
12104 break;
12105 case AXIS_DESCENDANT_OR_SELF:
12106 last = NULL;
12107 next = xmlXPathNextDescendantOrSelf;
12108 break;
12109 case AXIS_FOLLOWING:
12110 last = NULL;
12111 next = xmlXPathNextFollowing;
12112 break;
12113 case AXIS_FOLLOWING_SIBLING:
12114 last = NULL;
12115 next = xmlXPathNextFollowingSibling;
12116 break;
12117 case AXIS_NAMESPACE:
12118 first = NULL;
12119 last = NULL;
12120 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12121 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12122 break;
12123 case AXIS_PARENT:
12124 first = NULL;
12125 next = xmlXPathNextParent;
12126 break;
12127 case AXIS_PRECEDING:
12128 first = NULL;
12129 next = xmlXPathNextPrecedingInternal;
12130 break;
12131 case AXIS_PRECEDING_SIBLING:
12132 first = NULL;
12133 next = xmlXPathNextPrecedingSibling;
12134 break;
12135 case AXIS_SELF:
12136 first = NULL;
12137 last = NULL;
12138 next = xmlXPathNextSelf;
12139 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12140 break;
12141 }
12142
12143#ifdef DEBUG_STEP
Daniel Veillard074f37e2008-09-01 13:38:22 +000012144 xmlXPathDebugDumpStepAxis(op,
12145 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012146#endif
12147
12148 if (next == NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000012149 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012150 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012151 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012152 contextSeq = obj->nodesetval;
12153 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12154 xmlXPathReleaseObject(xpctxt, obj);
12155 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12156 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012157 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012158 /*
12159 * Predicate optimization ---------------------------------------------
12160 * If this step has a last predicate, which contains a position(),
12161 * then we'll optimize (although not exactly "position()", but only
12162 * the short-hand form, i.e., "[n]".
12163 *
12164 * Example - expression "/foo[parent::bar][1]":
Daniel Veillard45490ae2008-07-29 09:13:19 +000012165 *
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012166 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12167 * ROOT -- op->ch1
12168 * PREDICATE -- op->ch2 (predOp)
12169 * PREDICATE -- predOp->ch1 = [parent::bar]
12170 * SORT
12171 * COLLECT 'parent' 'name' 'node' bar
12172 * NODE
12173 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12174 *
12175 */
12176 maxPos = 0;
12177 predOp = NULL;
12178 hasPredicateRange = 0;
12179 hasAxisRange = 0;
12180 if (op->ch2 != -1) {
12181 /*
12182 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12183 */
12184 predOp = &ctxt->comp->steps[op->ch2];
12185 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12186 if (predOp->ch1 != -1) {
12187 /*
12188 * Use the next inner predicate operator.
12189 */
12190 predOp = &ctxt->comp->steps[predOp->ch1];
12191 hasPredicateRange = 1;
12192 } else {
12193 /*
12194 * There's no other predicate than the [n] predicate.
12195 */
12196 predOp = NULL;
12197 hasAxisRange = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012198 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012199 }
12200 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012201 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012202 /*
12203 * Axis traversal -----------------------------------------------------
12204 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012205 /*
12206 * 2.3 Node Tests
Daniel Veillard45490ae2008-07-29 09:13:19 +000012207 * - For the attribute axis, the principal node type is attribute.
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012208 * - For the namespace axis, the principal node type is namespace.
12209 * - For other axes, the principal node type is element.
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012210 *
12211 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012212 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012213 * select all element children of the context node
12214 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012215 oldContextNode = xpctxt->node;
12216 addNode = xmlXPathNodeSetAddUnique;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012217 outSeq = NULL;
12218 seq = NULL;
12219 outerContextNode = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012220 contextNode = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012221 contextIdx = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012222
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012223
12224 while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
Nick Wellnhofer62270532012-08-19 19:42:38 +020012225 xpctxt->node = contextSeq->nodeTab[contextIdx++];
Daniel Veillard45490ae2008-07-29 09:13:19 +000012226
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012227 if (seq == NULL) {
12228 seq = xmlXPathNodeSetCreate(NULL);
12229 if (seq == NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012230 total = 0;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012231 goto error;
12232 }
12233 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012234 /*
12235 * Traverse the axis and test the nodes.
12236 */
12237 pos = 0;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012238 cur = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012239 hasNsNodes = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012240 do {
12241 cur = next(ctxt, cur);
12242 if (cur == NULL)
12243 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012244
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012245 /*
12246 * QUESTION TODO: What does the "first" and "last" stuff do?
12247 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012248 if ((first != NULL) && (*first != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012249 if (*first == cur)
12250 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012251 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012252#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012253 (xmlXPathCmpNodesExt(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012254#else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012255 (xmlXPathCmpNodes(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012256#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012257 {
12258 break;
12259 }
12260 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012261 if ((last != NULL) && (*last != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012262 if (*last == cur)
12263 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012264 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012265#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012266 (xmlXPathCmpNodesExt(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012267#else
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012268 (xmlXPathCmpNodes(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012269#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012270 {
12271 break;
12272 }
12273 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012274
12275 total++;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012276
Daniel Veillardf06307e2001-07-03 10:35:50 +000012277#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012278 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12279#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +000012280
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012281 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012282 case NODE_TEST_NONE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012283 total = 0;
12284 STRANGE
12285 goto error;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012286 case NODE_TEST_TYPE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012287 /*
12288 * TODO: Don't we need to use
12289 * xmlXPathNodeSetAddNs() for namespace nodes here?
12290 * Surprisingly, some c14n tests fail, if we do this.
12291 */
12292 if (type == NODE_TYPE_NODE) {
12293 switch (cur->type) {
12294 case XML_DOCUMENT_NODE:
12295 case XML_HTML_DOCUMENT_NODE:
12296#ifdef LIBXML_DOCB_ENABLED
12297 case XML_DOCB_DOCUMENT_NODE:
12298#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +000012299 case XML_ELEMENT_NODE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012300 case XML_ATTRIBUTE_NODE:
12301 case XML_PI_NODE:
12302 case XML_COMMENT_NODE:
12303 case XML_CDATA_SECTION_NODE:
12304 case XML_TEXT_NODE:
12305 case XML_NAMESPACE_DECL:
12306 XP_TEST_HIT
12307 break;
12308 default:
12309 break;
12310 }
12311 } else if (cur->type == type) {
Kasimier T. Buchcik889b7622006-07-03 11:44:13 +000012312 if (type == XML_NAMESPACE_DECL)
12313 XP_TEST_HIT_NS
12314 else
12315 XP_TEST_HIT
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012316 } else if ((type == NODE_TYPE_TEXT) &&
12317 (cur->type == XML_CDATA_SECTION_NODE))
12318 {
12319 XP_TEST_HIT
12320 }
12321 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012322 case NODE_TEST_PI:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012323 if ((cur->type == XML_PI_NODE) &&
12324 ((name == NULL) || xmlStrEqual(name, cur->name)))
12325 {
12326 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012327 }
12328 break;
12329 case NODE_TEST_ALL:
12330 if (axis == AXIS_ATTRIBUTE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012331 if (cur->type == XML_ATTRIBUTE_NODE)
12332 {
12333 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012334 }
12335 } else if (axis == AXIS_NAMESPACE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012336 if (cur->type == XML_NAMESPACE_DECL)
12337 {
12338 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012339 }
12340 } else {
12341 if (cur->type == XML_ELEMENT_NODE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012342 if (prefix == NULL)
12343 {
12344 XP_TEST_HIT
12345
Daniel Veillardf06307e2001-07-03 10:35:50 +000012346 } else if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012347 (xmlStrEqual(URI, cur->ns->href)))
12348 {
12349 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012350 }
12351 }
12352 }
12353 break;
12354 case NODE_TEST_NS:{
12355 TODO;
12356 break;
12357 }
12358 case NODE_TEST_NAME:
Daniel Veillardfe3970e2006-11-23 16:08:30 +000012359 if (axis == AXIS_ATTRIBUTE) {
12360 if (cur->type != XML_ATTRIBUTE_NODE)
12361 break;
12362 } else if (axis == AXIS_NAMESPACE) {
12363 if (cur->type != XML_NAMESPACE_DECL)
12364 break;
12365 } else {
12366 if (cur->type != XML_ELEMENT_NODE)
12367 break;
12368 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012369 switch (cur->type) {
12370 case XML_ELEMENT_NODE:
12371 if (xmlStrEqual(name, cur->name)) {
12372 if (prefix == NULL) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012373 if (cur->ns == NULL)
12374 {
12375 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012376 }
12377 } else {
12378 if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012379 (xmlStrEqual(URI, cur->ns->href)))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012380 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012381 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012382 }
12383 }
12384 }
12385 break;
12386 case XML_ATTRIBUTE_NODE:{
12387 xmlAttrPtr attr = (xmlAttrPtr) cur;
12388
12389 if (xmlStrEqual(name, attr->name)) {
12390 if (prefix == NULL) {
12391 if ((attr->ns == NULL) ||
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012392 (attr->ns->prefix == NULL))
12393 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012394 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012395 }
12396 } else {
12397 if ((attr->ns != NULL) &&
12398 (xmlStrEqual(URI,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012399 attr->ns->href)))
12400 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012401 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012402 }
12403 }
12404 }
12405 break;
12406 }
12407 case XML_NAMESPACE_DECL:
12408 if (cur->type == XML_NAMESPACE_DECL) {
12409 xmlNsPtr ns = (xmlNsPtr) cur;
12410
12411 if ((ns->prefix != NULL) && (name != NULL)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012412 && (xmlStrEqual(ns->prefix, name)))
12413 {
12414 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012415 }
12416 }
12417 break;
12418 default:
12419 break;
12420 }
12421 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012422 } /* switch(test) */
12423 } while (cur != NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012424
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012425 goto apply_predicates;
12426
Daniel Veillard45490ae2008-07-29 09:13:19 +000012427axis_range_end: /* ----------------------------------------------------- */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012428 /*
12429 * We have a "/foo[n]", and position() = n was reached.
12430 * Note that we can have as well "/foo/::parent::foo[1]", so
12431 * a duplicate-aware merge is still needed.
12432 * Merge with the result.
12433 */
12434 if (outSeq == NULL) {
12435 outSeq = seq;
12436 seq = NULL;
12437 } else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012438 outSeq = mergeAndClear(outSeq, seq, 0);
12439 /*
12440 * Break if only a true/false result was requested.
12441 */
12442 if (toBool)
12443 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012444 continue;
12445
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012446first_hit: /* ---------------------------------------------------------- */
12447 /*
12448 * Break if only a true/false result was requested and
12449 * no predicates existed and a node test succeeded.
12450 */
12451 if (outSeq == NULL) {
12452 outSeq = seq;
12453 seq = NULL;
12454 } else
12455 outSeq = mergeAndClear(outSeq, seq, 0);
12456 break;
12457
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012458#ifdef DEBUG_STEP
12459 if (seq != NULL)
12460 nbMatches += seq->nodeNr;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012461#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012462
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012463apply_predicates: /* --------------------------------------------------- */
12464 /*
12465 * Apply predicates.
Daniel Veillard45490ae2008-07-29 09:13:19 +000012466 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012467 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12468 /*
12469 * E.g. when we have a "/foo[some expression][n]".
Daniel Veillard45490ae2008-07-29 09:13:19 +000012470 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012471 /*
12472 * QUESTION TODO: The old predicate evaluation took into
12473 * account location-sets.
12474 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12475 * Do we expect such a set here?
12476 * All what I learned now from the evaluation semantics
12477 * does not indicate that a location-set will be processed
12478 * here, so this looks OK.
Daniel Veillard45490ae2008-07-29 09:13:19 +000012479 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012480 /*
12481 * Iterate over all predicates, starting with the outermost
12482 * predicate.
12483 * TODO: Problem: we cannot execute the inner predicates first
12484 * since we cannot go back *up* the operator tree!
12485 * Options we have:
12486 * 1) Use of recursive functions (like is it currently done
12487 * via xmlXPathCompOpEval())
12488 * 2) Add a predicate evaluation information stack to the
12489 * context struct
12490 * 3) Change the way the operators are linked; we need a
12491 * "parent" field on xmlXPathStepOp
12492 *
12493 * For the moment, I'll try to solve this with a recursive
12494 * function: xmlXPathCompOpEvalPredicate().
Daniel Veillard45490ae2008-07-29 09:13:19 +000012495 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012496 size = seq->nodeNr;
12497 if (hasPredicateRange != 0)
12498 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12499 predOp, seq, size, maxPos, maxPos, hasNsNodes);
12500 else
12501 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12502 predOp, seq, size, hasNsNodes);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012503
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012504 if (ctxt->error != XPATH_EXPRESSION_OK) {
12505 total = 0;
12506 goto error;
12507 }
12508 /*
12509 * Add the filtered set of nodes to the result node set.
12510 */
12511 if (newSize == 0) {
12512 /*
12513 * The predicates filtered all nodes out.
12514 */
12515 xmlXPathNodeSetClear(seq, hasNsNodes);
12516 } else if (seq->nodeNr > 0) {
12517 /*
12518 * Add to result set.
12519 */
12520 if (outSeq == NULL) {
12521 if (size != newSize) {
12522 /*
12523 * We need to merge and clear here, since
12524 * the sequence will contained NULLed entries.
12525 */
12526 outSeq = mergeAndClear(NULL, seq, 1);
12527 } else {
12528 outSeq = seq;
12529 seq = NULL;
12530 }
12531 } else
12532 outSeq = mergeAndClear(outSeq, seq,
12533 (size != newSize) ? 1: 0);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012534 /*
12535 * Break if only a true/false result was requested.
12536 */
12537 if (toBool)
12538 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012539 }
12540 } else if (seq->nodeNr > 0) {
12541 /*
12542 * Add to result set.
12543 */
12544 if (outSeq == NULL) {
12545 outSeq = seq;
12546 seq = NULL;
12547 } else {
12548 outSeq = mergeAndClear(outSeq, seq, 0);
12549 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012550 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012551 }
12552
12553error:
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012554 if ((obj->boolval) && (obj->user != NULL)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012555 /*
12556 * QUESTION TODO: What does this do and why?
12557 * TODO: Do we have to do this also for the "error"
12558 * cleanup further down?
12559 */
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012560 ctxt->value->boolval = 1;
12561 ctxt->value->user = obj->user;
12562 obj->user = NULL;
12563 obj->boolval = 0;
12564 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012565 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012566
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012567 /*
12568 * Ensure we return at least an emtpy set.
12569 */
12570 if (outSeq == NULL) {
12571 if ((seq != NULL) && (seq->nodeNr == 0))
12572 outSeq = seq;
12573 else
12574 outSeq = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +000012575 /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012576 }
12577 if ((seq != NULL) && (seq != outSeq)) {
12578 xmlXPathFreeNodeSet(seq);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012579 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012580 /*
12581 * Hand over the result. Better to push the set also in
12582 * case of errors.
12583 */
12584 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12585 /*
12586 * Reset the context node.
12587 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012588 xpctxt->node = oldContextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012589
12590#ifdef DEBUG_STEP
12591 xmlGenericError(xmlGenericErrorContext,
12592 "\nExamined %d nodes, found %d nodes at that step\n",
12593 total, nbMatches);
12594#endif
12595
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012596 return(total);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012597}
12598
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012599static int
12600xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12601 xmlXPathStepOpPtr op, xmlNodePtr * first);
12602
Daniel Veillardf06307e2001-07-03 10:35:50 +000012603/**
12604 * xmlXPathCompOpEvalFirst:
12605 * @ctxt: the XPath parser context with the compiled expression
12606 * @op: an XPath compiled operation
12607 * @first: the first elem found so far
12608 *
12609 * Evaluate the Precompiled XPath operation searching only the first
12610 * element in document order
12611 *
12612 * Returns the number of examined objects.
12613 */
12614static int
12615xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12616 xmlXPathStepOpPtr op, xmlNodePtr * first)
12617{
12618 int total = 0, cur;
12619 xmlXPathCompExprPtr comp;
12620 xmlXPathObjectPtr arg1, arg2;
12621
Daniel Veillard556c6682001-10-06 09:59:51 +000012622 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012623 comp = ctxt->comp;
12624 switch (op->op) {
12625 case XPATH_OP_END:
12626 return (0);
12627 case XPATH_OP_UNION:
12628 total =
12629 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12630 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012631 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012632 if ((ctxt->value != NULL)
12633 && (ctxt->value->type == XPATH_NODESET)
12634 && (ctxt->value->nodesetval != NULL)
12635 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12636 /*
12637 * limit tree traversing to first node in the result
12638 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012639 /*
12640 * OPTIMIZE TODO: This implicitely sorts
12641 * the result, even if not needed. E.g. if the argument
12642 * of the count() function, no sorting is needed.
12643 * OPTIMIZE TODO: How do we know if the node-list wasn't
12644 * aready sorted?
12645 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012646 if (ctxt->value->nodesetval->nodeNr > 1)
12647 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012648 *first = ctxt->value->nodesetval->nodeTab[0];
12649 }
12650 cur =
12651 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12652 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012653 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012654 CHECK_TYPE0(XPATH_NODESET);
12655 arg2 = valuePop(ctxt);
12656
12657 CHECK_TYPE0(XPATH_NODESET);
12658 arg1 = valuePop(ctxt);
12659
12660 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12661 arg2->nodesetval);
12662 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012663 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012664 /* optimizer */
12665 if (total > cur)
12666 xmlXPathCompSwap(op);
12667 return (total + cur);
12668 case XPATH_OP_ROOT:
12669 xmlXPathRoot(ctxt);
12670 return (0);
12671 case XPATH_OP_NODE:
12672 if (op->ch1 != -1)
12673 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012674 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012675 if (op->ch2 != -1)
12676 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012677 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012678 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12679 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012680 return (total);
12681 case XPATH_OP_RESET:
12682 if (op->ch1 != -1)
12683 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012684 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012685 if (op->ch2 != -1)
12686 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012687 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012688 ctxt->context->node = NULL;
12689 return (total);
12690 case XPATH_OP_COLLECT:{
12691 if (op->ch1 == -1)
12692 return (total);
12693
12694 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012695 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012696
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012697 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012698 return (total);
12699 }
12700 case XPATH_OP_VALUE:
12701 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012702 xmlXPathCacheObjectCopy(ctxt->context,
12703 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012704 return (0);
12705 case XPATH_OP_SORT:
12706 if (op->ch1 != -1)
12707 total +=
12708 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12709 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012710 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012711 if ((ctxt->value != NULL)
12712 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012713 && (ctxt->value->nodesetval != NULL)
12714 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012715 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12716 return (total);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012717#ifdef XP_OPTIMIZED_FILTER_FIRST
12718 case XPATH_OP_FILTER:
Marius Wachtler2ddecc22010-10-12 09:09:07 +020012719 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012720 return (total);
12721#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000012722 default:
12723 return (xmlXPathCompOpEval(ctxt, op));
12724 }
12725}
12726
12727/**
12728 * xmlXPathCompOpEvalLast:
12729 * @ctxt: the XPath parser context with the compiled expression
12730 * @op: an XPath compiled operation
12731 * @last: the last elem found so far
12732 *
12733 * Evaluate the Precompiled XPath operation searching only the last
12734 * element in document order
12735 *
William M. Brack08171912003-12-29 02:52:11 +000012736 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000012737 */
12738static int
12739xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12740 xmlNodePtr * last)
12741{
12742 int total = 0, cur;
12743 xmlXPathCompExprPtr comp;
12744 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +000012745 xmlNodePtr bak;
12746 xmlDocPtr bakd;
12747 int pp;
12748 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012749
Daniel Veillard556c6682001-10-06 09:59:51 +000012750 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012751 comp = ctxt->comp;
12752 switch (op->op) {
12753 case XPATH_OP_END:
12754 return (0);
12755 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +000012756 bakd = ctxt->context->doc;
12757 bak = ctxt->context->node;
12758 pp = ctxt->context->proximityPosition;
12759 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012760 total =
12761 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012762 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012763 if ((ctxt->value != NULL)
12764 && (ctxt->value->type == XPATH_NODESET)
12765 && (ctxt->value->nodesetval != NULL)
12766 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12767 /*
12768 * limit tree traversing to first node in the result
12769 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012770 if (ctxt->value->nodesetval->nodeNr > 1)
12771 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012772 *last =
12773 ctxt->value->nodesetval->nodeTab[ctxt->value->
12774 nodesetval->nodeNr -
12775 1];
12776 }
William M. Brackce4fc562004-01-22 02:47:18 +000012777 ctxt->context->doc = bakd;
12778 ctxt->context->node = bak;
12779 ctxt->context->proximityPosition = pp;
12780 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012781 cur =
12782 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012783 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012784 if ((ctxt->value != NULL)
12785 && (ctxt->value->type == XPATH_NODESET)
12786 && (ctxt->value->nodesetval != NULL)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012787 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012788 }
12789 CHECK_TYPE0(XPATH_NODESET);
12790 arg2 = valuePop(ctxt);
12791
12792 CHECK_TYPE0(XPATH_NODESET);
12793 arg1 = valuePop(ctxt);
12794
12795 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12796 arg2->nodesetval);
12797 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012798 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012799 /* optimizer */
12800 if (total > cur)
12801 xmlXPathCompSwap(op);
12802 return (total + cur);
12803 case XPATH_OP_ROOT:
12804 xmlXPathRoot(ctxt);
12805 return (0);
12806 case XPATH_OP_NODE:
12807 if (op->ch1 != -1)
12808 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012809 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012810 if (op->ch2 != -1)
12811 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012812 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012813 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12814 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012815 return (total);
12816 case XPATH_OP_RESET:
12817 if (op->ch1 != -1)
12818 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012819 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012820 if (op->ch2 != -1)
12821 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012822 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012823 ctxt->context->node = NULL;
12824 return (total);
12825 case XPATH_OP_COLLECT:{
12826 if (op->ch1 == -1)
12827 return (0);
12828
12829 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012830 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012831
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012832 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012833 return (total);
12834 }
12835 case XPATH_OP_VALUE:
12836 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012837 xmlXPathCacheObjectCopy(ctxt->context,
12838 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012839 return (0);
12840 case XPATH_OP_SORT:
12841 if (op->ch1 != -1)
12842 total +=
12843 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12844 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012845 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012846 if ((ctxt->value != NULL)
12847 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012848 && (ctxt->value->nodesetval != NULL)
12849 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012850 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12851 return (total);
12852 default:
12853 return (xmlXPathCompOpEval(ctxt, op));
12854 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012855}
12856
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012857#ifdef XP_OPTIMIZED_FILTER_FIRST
12858static int
12859xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12860 xmlXPathStepOpPtr op, xmlNodePtr * first)
12861{
12862 int total = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012863 xmlXPathCompExprPtr comp;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012864 xmlXPathObjectPtr res;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012865 xmlXPathObjectPtr obj;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012866 xmlNodeSetPtr oldset;
12867 xmlNodePtr oldnode;
12868 xmlDocPtr oldDoc;
12869 int i;
12870
12871 CHECK_ERROR0;
12872 comp = ctxt->comp;
12873 /*
12874 * Optimization for ()[last()] selection i.e. the last elem
12875 */
12876 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12877 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12878 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12879 int f = comp->steps[op->ch2].ch1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012880
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012881 if ((f != -1) &&
12882 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12883 (comp->steps[f].value5 == NULL) &&
12884 (comp->steps[f].value == 0) &&
12885 (comp->steps[f].value4 != NULL) &&
12886 (xmlStrEqual
12887 (comp->steps[f].value4, BAD_CAST "last"))) {
12888 xmlNodePtr last = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012889
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012890 total +=
12891 xmlXPathCompOpEvalLast(ctxt,
12892 &comp->steps[op->ch1],
12893 &last);
12894 CHECK_ERROR0;
12895 /*
12896 * The nodeset should be in document order,
12897 * Keep only the last value
12898 */
12899 if ((ctxt->value != NULL) &&
12900 (ctxt->value->type == XPATH_NODESET) &&
12901 (ctxt->value->nodesetval != NULL) &&
12902 (ctxt->value->nodesetval->nodeTab != NULL) &&
12903 (ctxt->value->nodesetval->nodeNr > 1)) {
12904 ctxt->value->nodesetval->nodeTab[0] =
12905 ctxt->value->nodesetval->nodeTab[ctxt->
12906 value->
12907 nodesetval->
12908 nodeNr -
12909 1];
12910 ctxt->value->nodesetval->nodeNr = 1;
12911 *first = *(ctxt->value->nodesetval->nodeTab);
12912 }
12913 return (total);
12914 }
12915 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012916
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012917 if (op->ch1 != -1)
12918 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12919 CHECK_ERROR0;
12920 if (op->ch2 == -1)
12921 return (total);
12922 if (ctxt->value == NULL)
12923 return (total);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012924
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012925#ifdef LIBXML_XPTR_ENABLED
12926 oldnode = ctxt->context->node;
12927 /*
12928 * Hum are we filtering the result of an XPointer expression
12929 */
12930 if (ctxt->value->type == XPATH_LOCATIONSET) {
12931 xmlXPathObjectPtr tmp = NULL;
12932 xmlLocationSetPtr newlocset = NULL;
12933 xmlLocationSetPtr oldlocset;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012934
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012935 /*
12936 * Extract the old locset, and then evaluate the result of the
12937 * expression for all the element in the locset. use it to grow
12938 * up a new locset.
12939 */
12940 CHECK_TYPE0(XPATH_LOCATIONSET);
12941 obj = valuePop(ctxt);
12942 oldlocset = obj->user;
12943 ctxt->context->node = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012944
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012945 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12946 ctxt->context->contextSize = 0;
12947 ctxt->context->proximityPosition = 0;
12948 if (op->ch2 != -1)
12949 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12950 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012951 if (res != NULL) {
12952 xmlXPathReleaseObject(ctxt->context, res);
12953 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012954 valuePush(ctxt, obj);
12955 CHECK_ERROR0;
12956 return (total);
12957 }
12958 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012959
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012960 for (i = 0; i < oldlocset->locNr; i++) {
12961 /*
12962 * Run the evaluation with a node list made of a
12963 * single item in the nodelocset.
12964 */
12965 ctxt->context->node = oldlocset->locTab[i]->user;
12966 ctxt->context->contextSize = oldlocset->locNr;
12967 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012968 if (tmp == NULL) {
12969 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12970 ctxt->context->node);
12971 } else {
12972 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12973 ctxt->context->node);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012974 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012975 valuePush(ctxt, tmp);
12976 if (op->ch2 != -1)
12977 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12978 if (ctxt->error != XPATH_EXPRESSION_OK) {
12979 xmlXPathFreeObject(obj);
12980 return(0);
12981 }
12982 /*
12983 * The result of the evaluation need to be tested to
12984 * decided whether the filter succeeded or not
12985 */
12986 res = valuePop(ctxt);
12987 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12988 xmlXPtrLocationSetAdd(newlocset,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012989 xmlXPathCacheObjectCopy(ctxt->context,
12990 oldlocset->locTab[i]));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012991 }
12992 /*
12993 * Cleanup
12994 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012995 if (res != NULL) {
12996 xmlXPathReleaseObject(ctxt->context, res);
12997 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012998 if (ctxt->value == tmp) {
12999 valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013000 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013001 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013002 * REVISIT TODO: Don't create a temporary nodeset
13003 * for everly iteration.
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013004 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013005 /* OLD: xmlXPathFreeObject(res); */
13006 } else
Daniel Veillard45490ae2008-07-29 09:13:19 +000013007 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013008 ctxt->context->node = NULL;
13009 /*
13010 * Only put the first node in the result, then leave.
13011 */
13012 if (newlocset->locNr > 0) {
13013 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
13014 break;
13015 }
13016 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013017 if (tmp != NULL) {
13018 xmlXPathReleaseObject(ctxt->context, tmp);
13019 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013020 /*
13021 * The result is used as the new evaluation locset.
13022 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013023 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013024 ctxt->context->node = NULL;
13025 ctxt->context->contextSize = -1;
13026 ctxt->context->proximityPosition = -1;
13027 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13028 ctxt->context->node = oldnode;
13029 return (total);
13030 }
13031#endif /* LIBXML_XPTR_ENABLED */
Daniel Veillard45490ae2008-07-29 09:13:19 +000013032
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013033 /*
13034 * Extract the old set, and then evaluate the result of the
13035 * expression for all the element in the set. use it to grow
13036 * up a new set.
13037 */
13038 CHECK_TYPE0(XPATH_NODESET);
13039 obj = valuePop(ctxt);
13040 oldset = obj->nodesetval;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013041
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013042 oldnode = ctxt->context->node;
13043 oldDoc = ctxt->context->doc;
13044 ctxt->context->node = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013045
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013046 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13047 ctxt->context->contextSize = 0;
13048 ctxt->context->proximityPosition = 0;
13049 /* QUESTION TODO: Why was this code commented out?
13050 if (op->ch2 != -1)
13051 total +=
13052 xmlXPathCompOpEval(ctxt,
13053 &comp->steps[op->ch2]);
13054 CHECK_ERROR0;
13055 res = valuePop(ctxt);
13056 if (res != NULL)
13057 xmlXPathFreeObject(res);
13058 */
13059 valuePush(ctxt, obj);
13060 ctxt->context->node = oldnode;
13061 CHECK_ERROR0;
13062 } else {
13063 xmlNodeSetPtr newset;
13064 xmlXPathObjectPtr tmp = NULL;
13065 /*
13066 * Initialize the new set.
13067 * Also set the xpath document in case things like
13068 * key() evaluation are attempted on the predicate
Daniel Veillard45490ae2008-07-29 09:13:19 +000013069 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013070 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +000013071 /* XXX what if xmlXPathNodeSetCreate returned NULL? */
Daniel Veillard45490ae2008-07-29 09:13:19 +000013072
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013073 for (i = 0; i < oldset->nodeNr; i++) {
13074 /*
13075 * Run the evaluation with a node list made of
13076 * a single item in the nodeset.
13077 */
13078 ctxt->context->node = oldset->nodeTab[i];
13079 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13080 (oldset->nodeTab[i]->doc != NULL))
13081 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013082 if (tmp == NULL) {
13083 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13084 ctxt->context->node);
13085 } else {
13086 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13087 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013088 }
13089 valuePush(ctxt, tmp);
13090 ctxt->context->contextSize = oldset->nodeNr;
13091 ctxt->context->proximityPosition = i + 1;
13092 if (op->ch2 != -1)
13093 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13094 if (ctxt->error != XPATH_EXPRESSION_OK) {
13095 xmlXPathFreeNodeSet(newset);
13096 xmlXPathFreeObject(obj);
13097 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013098 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013099 /*
13100 * The result of the evaluation needs to be tested to
13101 * decide whether the filter succeeded or not
13102 */
13103 res = valuePop(ctxt);
13104 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13105 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013106 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013107 /*
13108 * Cleanup
13109 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013110 if (res != NULL) {
13111 xmlXPathReleaseObject(ctxt->context, res);
13112 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013113 if (ctxt->value == tmp) {
13114 valuePop(ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013115 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013116 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013117 * in order to avoid massive recreation inside this
13118 * loop.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013119 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000013120 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013121 } else
13122 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013123 ctxt->context->node = NULL;
13124 /*
13125 * Only put the first node in the result, then leave.
13126 */
13127 if (newset->nodeNr > 0) {
13128 *first = *(newset->nodeTab);
13129 break;
13130 }
13131 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013132 if (tmp != NULL) {
13133 xmlXPathReleaseObject(ctxt->context, tmp);
13134 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013135 /*
13136 * The result is used as the new evaluation set.
13137 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013138 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013139 ctxt->context->node = NULL;
13140 ctxt->context->contextSize = -1;
13141 ctxt->context->proximityPosition = -1;
13142 /* may want to move this past the '}' later */
13143 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013144 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013145 }
13146 ctxt->context->node = oldnode;
13147 return(total);
13148}
13149#endif /* XP_OPTIMIZED_FILTER_FIRST */
13150
Owen Taylor3473f882001-02-23 17:55:21 +000013151/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013152 * xmlXPathCompOpEval:
13153 * @ctxt: the XPath parser context with the compiled expression
13154 * @op: an XPath compiled operation
13155 *
13156 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000013157 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013158 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013159static int
13160xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13161{
13162 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013163 int equal, ret;
13164 xmlXPathCompExprPtr comp;
13165 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013166 xmlNodePtr bak;
13167 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000013168 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000013169 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013170
Daniel Veillard556c6682001-10-06 09:59:51 +000013171 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013172 comp = ctxt->comp;
13173 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013174 case XPATH_OP_END:
13175 return (0);
13176 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013177 bakd = ctxt->context->doc;
13178 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013179 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013180 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013181 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013182 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013183 xmlXPathBooleanFunction(ctxt, 1);
13184 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13185 return (total);
13186 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013187 ctxt->context->doc = bakd;
13188 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013189 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013190 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013191 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013192 if (ctxt->error) {
13193 xmlXPathFreeObject(arg2);
13194 return(0);
13195 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013196 xmlXPathBooleanFunction(ctxt, 1);
13197 arg1 = valuePop(ctxt);
13198 arg1->boolval &= arg2->boolval;
13199 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013200 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013201 return (total);
13202 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013203 bakd = ctxt->context->doc;
13204 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013205 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013206 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013207 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013208 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013209 xmlXPathBooleanFunction(ctxt, 1);
13210 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13211 return (total);
13212 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013213 ctxt->context->doc = bakd;
13214 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013215 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013216 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013217 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013218 if (ctxt->error) {
13219 xmlXPathFreeObject(arg2);
13220 return(0);
13221 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013222 xmlXPathBooleanFunction(ctxt, 1);
13223 arg1 = valuePop(ctxt);
13224 arg1->boolval |= arg2->boolval;
13225 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013226 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013227 return (total);
13228 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013229 bakd = ctxt->context->doc;
13230 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013231 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013232 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013233 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013234 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013235 ctxt->context->doc = bakd;
13236 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013237 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013238 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013239 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013240 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000013241 if (op->value)
Daniel Veillard45490ae2008-07-29 09:13:19 +000013242 equal = xmlXPathEqualValues(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +000013243 else
13244 equal = xmlXPathNotEqualValues(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013245 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013246 return (total);
13247 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013248 bakd = ctxt->context->doc;
13249 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013250 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013251 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013252 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013253 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013254 ctxt->context->doc = bakd;
13255 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013256 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013257 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013258 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013259 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013260 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013261 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013262 return (total);
13263 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013264 bakd = ctxt->context->doc;
13265 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013266 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013267 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013268 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013269 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013270 if (op->ch2 != -1) {
13271 ctxt->context->doc = bakd;
13272 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013273 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013274 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013275 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013276 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013277 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013278 if (op->value == 0)
13279 xmlXPathSubValues(ctxt);
13280 else if (op->value == 1)
13281 xmlXPathAddValues(ctxt);
13282 else if (op->value == 2)
13283 xmlXPathValueFlipSign(ctxt);
13284 else if (op->value == 3) {
13285 CAST_TO_NUMBER;
13286 CHECK_TYPE0(XPATH_NUMBER);
13287 }
13288 return (total);
13289 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013290 bakd = ctxt->context->doc;
13291 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013292 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013293 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013294 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013295 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013296 ctxt->context->doc = bakd;
13297 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013298 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013299 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013300 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013301 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013302 if (op->value == 0)
13303 xmlXPathMultValues(ctxt);
13304 else if (op->value == 1)
13305 xmlXPathDivValues(ctxt);
13306 else if (op->value == 2)
13307 xmlXPathModValues(ctxt);
13308 return (total);
13309 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013310 bakd = ctxt->context->doc;
13311 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013312 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013313 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013314 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013315 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013316 ctxt->context->doc = bakd;
13317 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013318 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013319 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013320 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013321 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013322 CHECK_TYPE0(XPATH_NODESET);
13323 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013324
Daniel Veillardf06307e2001-07-03 10:35:50 +000013325 CHECK_TYPE0(XPATH_NODESET);
13326 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013327
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013328 if ((arg1->nodesetval == NULL) ||
13329 ((arg2->nodesetval != NULL) &&
13330 (arg2->nodesetval->nodeNr != 0)))
13331 {
13332 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13333 arg2->nodesetval);
13334 }
13335
Daniel Veillardf06307e2001-07-03 10:35:50 +000013336 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013337 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013338 return (total);
13339 case XPATH_OP_ROOT:
13340 xmlXPathRoot(ctxt);
13341 return (total);
13342 case XPATH_OP_NODE:
13343 if (op->ch1 != -1)
13344 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013345 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013346 if (op->ch2 != -1)
13347 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013348 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013349 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13350 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013351 return (total);
13352 case XPATH_OP_RESET:
13353 if (op->ch1 != -1)
13354 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013355 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013356 if (op->ch2 != -1)
13357 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013358 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013359 ctxt->context->node = NULL;
13360 return (total);
13361 case XPATH_OP_COLLECT:{
13362 if (op->ch1 == -1)
13363 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000013364
Daniel Veillardf06307e2001-07-03 10:35:50 +000013365 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013366 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013367
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013368 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013369 return (total);
13370 }
13371 case XPATH_OP_VALUE:
13372 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013373 xmlXPathCacheObjectCopy(ctxt->context,
13374 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013375 return (total);
13376 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000013377 xmlXPathObjectPtr val;
13378
Daniel Veillardf06307e2001-07-03 10:35:50 +000013379 if (op->ch1 != -1)
13380 total +=
13381 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013382 if (op->value5 == NULL) {
13383 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13384 if (val == NULL) {
13385 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13386 return(0);
13387 }
13388 valuePush(ctxt, val);
13389 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013390 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013391
Daniel Veillardf06307e2001-07-03 10:35:50 +000013392 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13393 if (URI == NULL) {
13394 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013395 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13396 (char *) op->value4, (char *)op->value5);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080013397 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013398 return (total);
13399 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013400 val = xmlXPathVariableLookupNS(ctxt->context,
13401 op->value4, URI);
13402 if (val == NULL) {
13403 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13404 return(0);
13405 }
13406 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013407 }
13408 return (total);
13409 }
13410 case XPATH_OP_FUNCTION:{
13411 xmlXPathFunction func;
13412 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000013413 int i;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013414 int frame;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013415
Daniel Veillardf5048b32011-08-18 17:10:13 +080013416 frame = xmlXPathSetFrame(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013417 if (op->ch1 != -1)
13418 total +=
13419 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013420 if (ctxt->valueNr < op->value) {
13421 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013422 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013423 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013424 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard556c6682001-10-06 09:59:51 +000013425 return (total);
13426 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080013427 for (i = 0; i < op->value; i++) {
Daniel Veillard556c6682001-10-06 09:59:51 +000013428 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13429 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013430 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013431 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013432 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard556c6682001-10-06 09:59:51 +000013433 return (total);
13434 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080013435 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013436 if (op->cache != NULL)
William M. Brackad0e67c2004-12-01 14:35:10 +000013437 XML_CAST_FPTR(func) = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013438 else {
13439 const xmlChar *URI = NULL;
13440
13441 if (op->value5 == NULL)
13442 func =
13443 xmlXPathFunctionLookup(ctxt->context,
13444 op->value4);
13445 else {
13446 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13447 if (URI == NULL) {
13448 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013449 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13450 (char *)op->value4, (char *)op->value5);
Daniel Veillardf5048b32011-08-18 17:10:13 +080013451 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080013452 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013453 return (total);
13454 }
13455 func = xmlXPathFunctionLookupNS(ctxt->context,
13456 op->value4, URI);
13457 }
13458 if (func == NULL) {
13459 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013460 "xmlXPathCompOpEval: function %s not found\n",
13461 (char *)op->value4);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013462 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013463 }
William M. Brackad0e67c2004-12-01 14:35:10 +000013464 op->cache = XML_CAST_FPTR(func);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013465 op->cacheURI = (void *) URI;
13466 }
13467 oldFunc = ctxt->context->function;
13468 oldFuncURI = ctxt->context->functionURI;
13469 ctxt->context->function = op->value4;
13470 ctxt->context->functionURI = op->cacheURI;
13471 func(ctxt, op->value);
13472 ctxt->context->function = oldFunc;
13473 ctxt->context->functionURI = oldFuncURI;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013474 xmlXPathPopFrame(ctxt, frame);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013475 return (total);
13476 }
13477 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000013478 bakd = ctxt->context->doc;
13479 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000013480 pp = ctxt->context->proximityPosition;
13481 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013482 if (op->ch1 != -1)
13483 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
William M. Brack645a9242004-11-09 12:20:42 +000013484 ctxt->context->contextSize = cs;
13485 ctxt->context->proximityPosition = pp;
Daniel Veillard088bf112002-05-14 11:03:59 +000013486 ctxt->context->node = bak;
William M. Brack645a9242004-11-09 12:20:42 +000013487 ctxt->context->doc = bakd;
Daniel Veillard556c6682001-10-06 09:59:51 +000013488 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000013489 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013490 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000013491 ctxt->context->doc = bakd;
13492 ctxt->context->node = bak;
13493 CHECK_ERROR0;
13494 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013495 return (total);
13496 case XPATH_OP_PREDICATE:
13497 case XPATH_OP_FILTER:{
13498 xmlXPathObjectPtr res;
13499 xmlXPathObjectPtr obj, tmp;
13500 xmlNodeSetPtr newset = NULL;
13501 xmlNodeSetPtr oldset;
13502 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000013503 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013504 int i;
13505
13506 /*
13507 * Optimization for ()[1] selection i.e. the first elem
13508 */
13509 if ((op->ch1 != -1) && (op->ch2 != -1) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013510#ifdef XP_OPTIMIZED_FILTER_FIRST
13511 /*
13512 * FILTER TODO: Can we assume that the inner processing
13513 * will result in an ordered list if we have an
13514 * XPATH_OP_FILTER?
13515 * What about an additional field or flag on
13516 * xmlXPathObject like @sorted ? This way we wouln'd need
13517 * to assume anything, so it would be more robust and
13518 * easier to optimize.
13519 */
13520 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13521 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13522#else
13523 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13524#endif
13525 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013526 xmlXPathObjectPtr val;
13527
13528 val = comp->steps[op->ch2].value4;
13529 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13530 (val->floatval == 1.0)) {
13531 xmlNodePtr first = NULL;
13532
13533 total +=
13534 xmlXPathCompOpEvalFirst(ctxt,
13535 &comp->steps[op->ch1],
13536 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000013537 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013538 /*
13539 * The nodeset should be in document order,
13540 * Keep only the first value
13541 */
13542 if ((ctxt->value != NULL) &&
13543 (ctxt->value->type == XPATH_NODESET) &&
13544 (ctxt->value->nodesetval != NULL) &&
13545 (ctxt->value->nodesetval->nodeNr > 1))
13546 ctxt->value->nodesetval->nodeNr = 1;
13547 return (total);
13548 }
13549 }
13550 /*
13551 * Optimization for ()[last()] selection i.e. the last elem
13552 */
13553 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13554 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13555 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13556 int f = comp->steps[op->ch2].ch1;
13557
13558 if ((f != -1) &&
13559 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13560 (comp->steps[f].value5 == NULL) &&
13561 (comp->steps[f].value == 0) &&
13562 (comp->steps[f].value4 != NULL) &&
13563 (xmlStrEqual
13564 (comp->steps[f].value4, BAD_CAST "last"))) {
13565 xmlNodePtr last = NULL;
13566
13567 total +=
13568 xmlXPathCompOpEvalLast(ctxt,
13569 &comp->steps[op->ch1],
13570 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000013571 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013572 /*
13573 * The nodeset should be in document order,
13574 * Keep only the last value
13575 */
13576 if ((ctxt->value != NULL) &&
13577 (ctxt->value->type == XPATH_NODESET) &&
13578 (ctxt->value->nodesetval != NULL) &&
13579 (ctxt->value->nodesetval->nodeTab != NULL) &&
13580 (ctxt->value->nodesetval->nodeNr > 1)) {
13581 ctxt->value->nodesetval->nodeTab[0] =
13582 ctxt->value->nodesetval->nodeTab[ctxt->
13583 value->
13584 nodesetval->
13585 nodeNr -
13586 1];
13587 ctxt->value->nodesetval->nodeNr = 1;
13588 }
13589 return (total);
13590 }
13591 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013592 /*
13593 * Process inner predicates first.
13594 * Example "index[parent::book][1]":
13595 * ...
13596 * PREDICATE <-- we are here "[1]"
13597 * PREDICATE <-- process "[parent::book]" first
13598 * SORT
13599 * COLLECT 'parent' 'name' 'node' book
13600 * NODE
13601 * ELEM Object is a number : 1
13602 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013603 if (op->ch1 != -1)
13604 total +=
13605 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013606 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013607 if (op->ch2 == -1)
13608 return (total);
13609 if (ctxt->value == NULL)
13610 return (total);
13611
13612 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013613
13614#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013615 /*
13616 * Hum are we filtering the result of an XPointer expression
13617 */
13618 if (ctxt->value->type == XPATH_LOCATIONSET) {
13619 xmlLocationSetPtr newlocset = NULL;
13620 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013621
Daniel Veillardf06307e2001-07-03 10:35:50 +000013622 /*
13623 * Extract the old locset, and then evaluate the result of the
13624 * expression for all the element in the locset. use it to grow
13625 * up a new locset.
13626 */
13627 CHECK_TYPE0(XPATH_LOCATIONSET);
13628 obj = valuePop(ctxt);
13629 oldlocset = obj->user;
13630 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013631
Daniel Veillardf06307e2001-07-03 10:35:50 +000013632 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13633 ctxt->context->contextSize = 0;
13634 ctxt->context->proximityPosition = 0;
13635 if (op->ch2 != -1)
13636 total +=
13637 xmlXPathCompOpEval(ctxt,
13638 &comp->steps[op->ch2]);
13639 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013640 if (res != NULL) {
13641 xmlXPathReleaseObject(ctxt->context, res);
13642 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013643 valuePush(ctxt, obj);
13644 CHECK_ERROR0;
13645 return (total);
13646 }
13647 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013648
Daniel Veillardf06307e2001-07-03 10:35:50 +000013649 for (i = 0; i < oldlocset->locNr; i++) {
13650 /*
13651 * Run the evaluation with a node list made of a
13652 * single item in the nodelocset.
13653 */
13654 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013655 ctxt->context->contextSize = oldlocset->locNr;
13656 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013657 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13658 ctxt->context->node);
William M. Brackf7eb7942003-12-31 07:59:17 +000013659 valuePush(ctxt, tmp);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013660
Daniel Veillardf06307e2001-07-03 10:35:50 +000013661 if (op->ch2 != -1)
13662 total +=
13663 xmlXPathCompOpEval(ctxt,
13664 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013665 if (ctxt->error != XPATH_EXPRESSION_OK) {
13666 xmlXPathFreeObject(obj);
13667 return(0);
13668 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013669
Daniel Veillardf06307e2001-07-03 10:35:50 +000013670 /*
13671 * The result of the evaluation need to be tested to
13672 * decided whether the filter succeeded or not
13673 */
13674 res = valuePop(ctxt);
13675 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13676 xmlXPtrLocationSetAdd(newlocset,
13677 xmlXPathObjectCopy
13678 (oldlocset->locTab[i]));
13679 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013680
Daniel Veillardf06307e2001-07-03 10:35:50 +000013681 /*
13682 * Cleanup
13683 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013684 if (res != NULL) {
13685 xmlXPathReleaseObject(ctxt->context, res);
13686 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013687 if (ctxt->value == tmp) {
13688 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013689 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013690 }
13691
13692 ctxt->context->node = NULL;
13693 }
13694
13695 /*
13696 * The result is used as the new evaluation locset.
13697 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013698 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013699 ctxt->context->node = NULL;
13700 ctxt->context->contextSize = -1;
13701 ctxt->context->proximityPosition = -1;
13702 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13703 ctxt->context->node = oldnode;
13704 return (total);
13705 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013706#endif /* LIBXML_XPTR_ENABLED */
13707
Daniel Veillardf06307e2001-07-03 10:35:50 +000013708 /*
13709 * Extract the old set, and then evaluate the result of the
13710 * expression for all the element in the set. use it to grow
13711 * up a new set.
13712 */
13713 CHECK_TYPE0(XPATH_NODESET);
13714 obj = valuePop(ctxt);
13715 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000013716
Daniel Veillardf06307e2001-07-03 10:35:50 +000013717 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000013718 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013719 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013720
Daniel Veillardf06307e2001-07-03 10:35:50 +000013721 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13722 ctxt->context->contextSize = 0;
13723 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000013724/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000013725 if (op->ch2 != -1)
13726 total +=
13727 xmlXPathCompOpEval(ctxt,
13728 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013729 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013730 res = valuePop(ctxt);
13731 if (res != NULL)
13732 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000013733*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000013734 valuePush(ctxt, obj);
13735 ctxt->context->node = oldnode;
13736 CHECK_ERROR0;
13737 } else {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013738 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013739 /*
13740 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000013741 * Also set the xpath document in case things like
13742 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000013743 */
13744 newset = xmlXPathNodeSetCreate(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013745 /*
13746 * SPEC XPath 1.0:
13747 * "For each node in the node-set to be filtered, the
13748 * PredicateExpr is evaluated with that node as the
13749 * context node, with the number of nodes in the
13750 * node-set as the context size, and with the proximity
13751 * position of the node in the node-set with respect to
13752 * the axis as the context position;"
13753 * @oldset is the node-set" to be filtered.
13754 *
13755 * SPEC XPath 1.0:
13756 * "only predicates change the context position and
13757 * context size (see [2.4 Predicates])."
13758 * Example:
13759 * node-set context pos
13760 * nA 1
13761 * nB 2
13762 * nC 3
13763 * After applying predicate [position() > 1] :
13764 * node-set context pos
13765 * nB 1
13766 * nC 2
13767 *
13768 * removed the first node in the node-set, then
Daniel Veillard45490ae2008-07-29 09:13:19 +000013769 * the context position of the
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013770 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013771 for (i = 0; i < oldset->nodeNr; i++) {
13772 /*
13773 * Run the evaluation with a node list made of
13774 * a single item in the nodeset.
13775 */
13776 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000013777 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13778 (oldset->nodeTab[i]->doc != NULL))
13779 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013780 if (tmp == NULL) {
13781 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13782 ctxt->context->node);
13783 } else {
13784 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13785 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013786 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013787 valuePush(ctxt, tmp);
13788 ctxt->context->contextSize = oldset->nodeNr;
13789 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013790 /*
13791 * Evaluate the predicate against the context node.
13792 * Can/should we optimize position() predicates
13793 * here (e.g. "[1]")?
13794 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013795 if (op->ch2 != -1)
13796 total +=
13797 xmlXPathCompOpEval(ctxt,
13798 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013799 if (ctxt->error != XPATH_EXPRESSION_OK) {
13800 xmlXPathFreeNodeSet(newset);
13801 xmlXPathFreeObject(obj);
13802 return(0);
13803 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013804
Daniel Veillardf06307e2001-07-03 10:35:50 +000013805 /*
William M. Brack08171912003-12-29 02:52:11 +000013806 * The result of the evaluation needs to be tested to
13807 * decide whether the filter succeeded or not
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013808 */
13809 /*
13810 * OPTIMIZE TODO: Can we use
13811 * xmlXPathNodeSetAdd*Unique()* instead?
13812 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013813 res = valuePop(ctxt);
13814 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13815 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13816 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013817
Daniel Veillardf06307e2001-07-03 10:35:50 +000013818 /*
13819 * Cleanup
13820 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013821 if (res != NULL) {
13822 xmlXPathReleaseObject(ctxt->context, res);
13823 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013824 if (ctxt->value == tmp) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013825 valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013826 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013827 /*
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013828 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013829 * in order to avoid massive recreation inside this
13830 * loop.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013831 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013832 } else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013833 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013834 ctxt->context->node = NULL;
13835 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013836 if (tmp != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013837 xmlXPathReleaseObject(ctxt->context, tmp);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013838 /*
13839 * The result is used as the new evaluation set.
13840 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013841 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013842 ctxt->context->node = NULL;
13843 ctxt->context->contextSize = -1;
13844 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000013845 /* may want to move this past the '}' later */
13846 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013847 valuePush(ctxt,
13848 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013849 }
13850 ctxt->context->node = oldnode;
13851 return (total);
13852 }
13853 case XPATH_OP_SORT:
13854 if (op->ch1 != -1)
13855 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013856 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013857 if ((ctxt->value != NULL) &&
13858 (ctxt->value->type == XPATH_NODESET) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013859 (ctxt->value->nodesetval != NULL) &&
13860 (ctxt->value->nodesetval->nodeNr > 1))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013861 {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013862 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013863 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013864 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013865#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013866 case XPATH_OP_RANGETO:{
13867 xmlXPathObjectPtr range;
13868 xmlXPathObjectPtr res, obj;
13869 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000013870 xmlLocationSetPtr newlocset = NULL;
13871 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013872 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000013873 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013874
Daniel Veillardf06307e2001-07-03 10:35:50 +000013875 if (op->ch1 != -1)
13876 total +=
13877 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13878 if (op->ch2 == -1)
13879 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013880
William M. Brack08171912003-12-29 02:52:11 +000013881 if (ctxt->value->type == XPATH_LOCATIONSET) {
13882 /*
13883 * Extract the old locset, and then evaluate the result of the
13884 * expression for all the element in the locset. use it to grow
13885 * up a new locset.
13886 */
13887 CHECK_TYPE0(XPATH_LOCATIONSET);
13888 obj = valuePop(ctxt);
13889 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013890
William M. Brack08171912003-12-29 02:52:11 +000013891 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000013892 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000013893 ctxt->context->contextSize = 0;
13894 ctxt->context->proximityPosition = 0;
13895 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13896 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013897 if (res != NULL) {
13898 xmlXPathReleaseObject(ctxt->context, res);
13899 }
William M. Brack08171912003-12-29 02:52:11 +000013900 valuePush(ctxt, obj);
13901 CHECK_ERROR0;
13902 return (total);
13903 }
13904 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013905
William M. Brack08171912003-12-29 02:52:11 +000013906 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013907 /*
William M. Brack08171912003-12-29 02:52:11 +000013908 * Run the evaluation with a node list made of a
13909 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000013910 */
William M. Brackf7eb7942003-12-31 07:59:17 +000013911 ctxt->context->node = oldlocset->locTab[i]->user;
13912 ctxt->context->contextSize = oldlocset->locNr;
13913 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013914 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13915 ctxt->context->node);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013916 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013917
Daniel Veillardf06307e2001-07-03 10:35:50 +000013918 if (op->ch2 != -1)
13919 total +=
13920 xmlXPathCompOpEval(ctxt,
13921 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013922 if (ctxt->error != XPATH_EXPRESSION_OK) {
13923 xmlXPathFreeObject(obj);
13924 return(0);
13925 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013926
Daniel Veillardf06307e2001-07-03 10:35:50 +000013927 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000013928 if (res->type == XPATH_LOCATIONSET) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000013929 xmlLocationSetPtr rloc =
William M. Brack72ee48d2003-12-30 08:30:19 +000013930 (xmlLocationSetPtr)res->user;
13931 for (j=0; j<rloc->locNr; j++) {
13932 range = xmlXPtrNewRange(
13933 oldlocset->locTab[i]->user,
13934 oldlocset->locTab[i]->index,
13935 rloc->locTab[j]->user2,
13936 rloc->locTab[j]->index2);
13937 if (range != NULL) {
13938 xmlXPtrLocationSetAdd(newlocset, range);
13939 }
13940 }
13941 } else {
13942 range = xmlXPtrNewRangeNodeObject(
13943 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13944 if (range != NULL) {
13945 xmlXPtrLocationSetAdd(newlocset,range);
13946 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013947 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013948
Daniel Veillardf06307e2001-07-03 10:35:50 +000013949 /*
13950 * Cleanup
13951 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013952 if (res != NULL) {
13953 xmlXPathReleaseObject(ctxt->context, res);
13954 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013955 if (ctxt->value == tmp) {
13956 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013957 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013958 }
13959
13960 ctxt->context->node = NULL;
13961 }
William M. Brack72ee48d2003-12-30 08:30:19 +000013962 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000013963 CHECK_TYPE0(XPATH_NODESET);
13964 obj = valuePop(ctxt);
13965 oldset = obj->nodesetval;
13966 ctxt->context->node = NULL;
13967
13968 newlocset = xmlXPtrLocationSetCreate(NULL);
13969
13970 if (oldset != NULL) {
13971 for (i = 0; i < oldset->nodeNr; i++) {
13972 /*
13973 * Run the evaluation with a node list made of a single item
13974 * in the nodeset.
13975 */
13976 ctxt->context->node = oldset->nodeTab[i];
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013977 /*
13978 * OPTIMIZE TODO: Avoid recreation for every iteration.
13979 */
13980 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13981 ctxt->context->node);
William M. Brack08171912003-12-29 02:52:11 +000013982 valuePush(ctxt, tmp);
13983
13984 if (op->ch2 != -1)
13985 total +=
13986 xmlXPathCompOpEval(ctxt,
13987 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013988 if (ctxt->error != XPATH_EXPRESSION_OK) {
13989 xmlXPathFreeObject(obj);
13990 return(0);
13991 }
William M. Brack08171912003-12-29 02:52:11 +000013992
William M. Brack08171912003-12-29 02:52:11 +000013993 res = valuePop(ctxt);
13994 range =
13995 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13996 res);
13997 if (range != NULL) {
13998 xmlXPtrLocationSetAdd(newlocset, range);
13999 }
14000
14001 /*
14002 * Cleanup
14003 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014004 if (res != NULL) {
14005 xmlXPathReleaseObject(ctxt->context, res);
14006 }
William M. Brack08171912003-12-29 02:52:11 +000014007 if (ctxt->value == tmp) {
14008 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014009 xmlXPathReleaseObject(ctxt->context, res);
William M. Brack08171912003-12-29 02:52:11 +000014010 }
14011
14012 ctxt->context->node = NULL;
14013 }
14014 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014015 }
14016
14017 /*
14018 * The result is used as the new evaluation set.
14019 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014020 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000014021 ctxt->context->node = NULL;
14022 ctxt->context->contextSize = -1;
14023 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000014024 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000014025 return (total);
14026 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014027#endif /* LIBXML_XPTR_ENABLED */
14028 }
14029 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000014030 "XPath: unknown precompiled operation %d\n", op->op);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080014031 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf06307e2001-07-03 10:35:50 +000014032 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014033}
14034
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014035/**
14036 * xmlXPathCompOpEvalToBoolean:
14037 * @ctxt: the XPath parser context
14038 *
14039 * Evaluates if the expression evaluates to true.
14040 *
14041 * Returns 1 if true, 0 if false and -1 on API or internal errors.
14042 */
14043static int
14044xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014045 xmlXPathStepOpPtr op,
14046 int isPredicate)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014047{
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014048 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014049
14050start:
14051 /* comp = ctxt->comp; */
14052 switch (op->op) {
14053 case XPATH_OP_END:
14054 return (0);
14055 case XPATH_OP_VALUE:
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014056 resObj = (xmlXPathObjectPtr) op->value4;
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000014057 if (isPredicate)
14058 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14059 return(xmlXPathCastToBoolean(resObj));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014060 case XPATH_OP_SORT:
14061 /*
14062 * We don't need sorting for boolean results. Skip this one.
14063 */
14064 if (op->ch1 != -1) {
14065 op = &ctxt->comp->steps[op->ch1];
14066 goto start;
14067 }
14068 return(0);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014069 case XPATH_OP_COLLECT:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014070 if (op->ch1 == -1)
14071 return(0);
14072
14073 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14074 if (ctxt->error != XPATH_EXPRESSION_OK)
14075 return(-1);
14076
14077 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14078 if (ctxt->error != XPATH_EXPRESSION_OK)
14079 return(-1);
14080
14081 resObj = valuePop(ctxt);
14082 if (resObj == NULL)
14083 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014084 break;
14085 default:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014086 /*
14087 * Fallback to call xmlXPathCompOpEval().
14088 */
14089 xmlXPathCompOpEval(ctxt, op);
14090 if (ctxt->error != XPATH_EXPRESSION_OK)
14091 return(-1);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014092
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014093 resObj = valuePop(ctxt);
14094 if (resObj == NULL)
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000014095 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014096 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014097 }
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014098
14099 if (resObj) {
14100 int res;
14101
14102 if (resObj->type == XPATH_BOOLEAN) {
14103 res = resObj->boolval;
14104 } else if (isPredicate) {
14105 /*
14106 * For predicates a result of type "number" is handled
14107 * differently:
14108 * SPEC XPath 1.0:
14109 * "If the result is a number, the result will be converted
14110 * to true if the number is equal to the context position
14111 * and will be converted to false otherwise;"
14112 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000014113 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014114 } else {
14115 res = xmlXPathCastToBoolean(resObj);
14116 }
14117 xmlXPathReleaseObject(ctxt->context, resObj);
14118 return(res);
14119 }
14120
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014121 return(0);
14122}
14123
Daniel Veillard56de87e2005-02-16 00:22:29 +000014124#ifdef XPATH_STREAMING
14125/**
14126 * xmlXPathRunStreamEval:
14127 * @ctxt: the XPath parser context with the compiled expression
14128 *
14129 * Evaluate the Precompiled Streamable XPath expression in the given context.
14130 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014131static int
14132xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14133 xmlXPathObjectPtr *resultSeq, int toBool)
14134{
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014135 int max_depth, min_depth;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014136 int from_root;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014137 int ret, depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014138 int eval_all_nodes;
William M. Brack12d37ab2005-02-21 13:54:07 +000014139 xmlNodePtr cur = NULL, limit = NULL;
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014140 xmlStreamCtxtPtr patstream = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014141
14142 int nb_nodes = 0;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014143
14144 if ((ctxt == NULL) || (comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014145 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014146 max_depth = xmlPatternMaxDepth(comp);
14147 if (max_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014148 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014149 if (max_depth == -2)
14150 max_depth = 10000;
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014151 min_depth = xmlPatternMinDepth(comp);
14152 if (min_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014153 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014154 from_root = xmlPatternFromRoot(comp);
14155 if (from_root < 0)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014156 return(-1);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014157#if 0
14158 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14159#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000014160
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014161 if (! toBool) {
14162 if (resultSeq == NULL)
14163 return(-1);
14164 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14165 if (*resultSeq == NULL)
14166 return(-1);
14167 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014168
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014169 /*
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014170 * handle the special cases of "/" amd "." being matched
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014171 */
14172 if (min_depth == 0) {
14173 if (from_root) {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014174 /* Select "/" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014175 if (toBool)
14176 return(1);
14177 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14178 (xmlNodePtr) ctxt->doc);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014179 } else {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014180 /* Select "self::node()" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014181 if (toBool)
14182 return(1);
14183 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014184 }
14185 }
14186 if (max_depth == 0) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014187 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014188 }
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014189
Daniel Veillard56de87e2005-02-16 00:22:29 +000014190 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000014191 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014192 } else if (ctxt->node != NULL) {
14193 switch (ctxt->node->type) {
14194 case XML_ELEMENT_NODE:
14195 case XML_DOCUMENT_NODE:
14196 case XML_DOCUMENT_FRAG_NODE:
14197 case XML_HTML_DOCUMENT_NODE:
14198#ifdef LIBXML_DOCB_ENABLED
14199 case XML_DOCB_DOCUMENT_NODE:
14200#endif
14201 cur = ctxt->node;
14202 break;
14203 case XML_ATTRIBUTE_NODE:
14204 case XML_TEXT_NODE:
14205 case XML_CDATA_SECTION_NODE:
14206 case XML_ENTITY_REF_NODE:
14207 case XML_ENTITY_NODE:
14208 case XML_PI_NODE:
14209 case XML_COMMENT_NODE:
14210 case XML_NOTATION_NODE:
14211 case XML_DTD_NODE:
14212 case XML_DOCUMENT_TYPE_NODE:
14213 case XML_ELEMENT_DECL:
14214 case XML_ATTRIBUTE_DECL:
14215 case XML_ENTITY_DECL:
14216 case XML_NAMESPACE_DECL:
14217 case XML_XINCLUDE_START:
14218 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000014219 break;
14220 }
14221 limit = cur;
14222 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014223 if (cur == NULL) {
14224 return(0);
14225 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014226
14227 patstream = xmlPatternGetStreamCtxt(comp);
14228 if (patstream == NULL) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014229 /*
14230 * QUESTION TODO: Is this an error?
14231 */
14232 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014233 }
14234
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014235 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014236
Daniel Veillard56de87e2005-02-16 00:22:29 +000014237 if (from_root) {
14238 ret = xmlStreamPush(patstream, NULL, NULL);
14239 if (ret < 0) {
14240 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014241 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014242 goto return_1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014243 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014244 }
14245 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014246 depth = 0;
14247 goto scan_children;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014248next_node:
Daniel Veillardd3ff7ef2006-02-27 19:43:17 +000014249 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014250 nb_nodes++;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014251
14252 switch (cur->type) {
14253 case XML_ELEMENT_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014254 case XML_TEXT_NODE:
14255 case XML_CDATA_SECTION_NODE:
14256 case XML_COMMENT_NODE:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014257 case XML_PI_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014258 if (cur->type == XML_ELEMENT_NODE) {
14259 ret = xmlStreamPush(patstream, cur->name,
Daniel Veillard56de87e2005-02-16 00:22:29 +000014260 (cur->ns ? cur->ns->href : NULL));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014261 } else if (eval_all_nodes)
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014262 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14263 else
14264 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014265
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014266 if (ret < 0) {
14267 /* NOP. */
14268 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014269 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014270 goto return_1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014271 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014272 }
14273 if ((cur->children == NULL) || (depth >= max_depth)) {
14274 ret = xmlStreamPop(patstream);
14275 while (cur->next != NULL) {
14276 cur = cur->next;
14277 if ((cur->type != XML_ENTITY_DECL) &&
14278 (cur->type != XML_DTD_NODE))
14279 goto next_node;
14280 }
14281 }
14282 default:
14283 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014284 }
14285
Daniel Veillard56de87e2005-02-16 00:22:29 +000014286scan_children:
Daniel Veillard3e62adb2012-08-09 14:24:02 +080014287 if (cur->type == XML_NAMESPACE_DECL) break;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014288 if ((cur->children != NULL) && (depth < max_depth)) {
14289 /*
Daniel Veillard45490ae2008-07-29 09:13:19 +000014290 * Do not descend on entities declarations
Daniel Veillard56de87e2005-02-16 00:22:29 +000014291 */
14292 if (cur->children->type != XML_ENTITY_DECL) {
14293 cur = cur->children;
14294 depth++;
14295 /*
14296 * Skip DTDs
14297 */
14298 if (cur->type != XML_DTD_NODE)
14299 continue;
14300 }
14301 }
14302
14303 if (cur == limit)
14304 break;
14305
14306 while (cur->next != NULL) {
14307 cur = cur->next;
14308 if ((cur->type != XML_ENTITY_DECL) &&
14309 (cur->type != XML_DTD_NODE))
14310 goto next_node;
14311 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014312
Daniel Veillard56de87e2005-02-16 00:22:29 +000014313 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014314 cur = cur->parent;
14315 depth--;
14316 if ((cur == NULL) || (cur == limit))
14317 goto done;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014318 if (cur->type == XML_ELEMENT_NODE) {
14319 ret = xmlStreamPop(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014320 } else if ((eval_all_nodes) &&
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014321 ((cur->type == XML_TEXT_NODE) ||
14322 (cur->type == XML_CDATA_SECTION_NODE) ||
14323 (cur->type == XML_COMMENT_NODE) ||
14324 (cur->type == XML_PI_NODE)))
14325 {
14326 ret = xmlStreamPop(patstream);
14327 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014328 if (cur->next != NULL) {
14329 cur = cur->next;
14330 break;
14331 }
14332 } while (cur != NULL);
14333
14334 } while ((cur != NULL) && (depth >= 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014335
Daniel Veillard56de87e2005-02-16 00:22:29 +000014336done:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014337
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014338#if 0
14339 printf("stream eval: checked %d nodes selected %d\n",
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014340 nb_nodes, retObj->nodesetval->nodeNr);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014341#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014342
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014343 if (patstream)
14344 xmlFreeStreamCtxt(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014345 return(0);
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014346
14347return_1:
14348 if (patstream)
14349 xmlFreeStreamCtxt(patstream);
14350 return(1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014351}
14352#endif /* XPATH_STREAMING */
14353
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014354/**
14355 * xmlXPathRunEval:
14356 * @ctxt: the XPath parser context with the compiled expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014357 * @toBool: evaluate to a boolean result
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014358 *
14359 * Evaluate the Precompiled XPath expression in the given context.
14360 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014361static int
14362xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14363{
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014364 xmlXPathCompExprPtr comp;
14365
14366 if ((ctxt == NULL) || (ctxt->comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014367 return(-1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014368
14369 if (ctxt->valueTab == NULL) {
14370 /* Allocate the value stack */
Daniel Veillard45490ae2008-07-29 09:13:19 +000014371 ctxt->valueTab = (xmlXPathObjectPtr *)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014372 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14373 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000014374 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014375 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014376 }
14377 ctxt->valueNr = 0;
14378 ctxt->valueMax = 10;
14379 ctxt->value = NULL;
Daniel Veillardf5048b32011-08-18 17:10:13 +080014380 ctxt->valueFrame = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014381 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014382#ifdef XPATH_STREAMING
14383 if (ctxt->comp->stream) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014384 int res;
14385
14386 if (toBool) {
14387 /*
14388 * Evaluation to boolean result.
14389 */
14390 res = xmlXPathRunStreamEval(ctxt->context,
14391 ctxt->comp->stream, NULL, 1);
14392 if (res != -1)
14393 return(res);
14394 } else {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014395 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014396
14397 /*
14398 * Evaluation to a sequence.
14399 */
14400 res = xmlXPathRunStreamEval(ctxt->context,
14401 ctxt->comp->stream, &resObj, 0);
14402
14403 if ((res != -1) && (resObj != NULL)) {
14404 valuePush(ctxt, resObj);
14405 return(0);
14406 }
14407 if (resObj != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +000014408 xmlXPathReleaseObject(ctxt->context, resObj);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014409 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014410 /*
14411 * QUESTION TODO: This falls back to normal XPath evaluation
14412 * if res == -1. Is this intended?
14413 */
Daniel Veillard56de87e2005-02-16 00:22:29 +000014414 }
14415#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014416 comp = ctxt->comp;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014417 if (comp->last < 0) {
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014418 xmlGenericError(xmlGenericErrorContext,
14419 "xmlXPathRunEval: last is less than zero\n");
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014420 return(-1);
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014421 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014422 if (toBool)
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014423 return(xmlXPathCompOpEvalToBoolean(ctxt,
14424 &comp->steps[comp->last], 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014425 else
14426 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14427
14428 return(0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014429}
14430
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014431/************************************************************************
14432 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +000014433 * Public interfaces *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014434 * *
14435 ************************************************************************/
14436
14437/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014438 * xmlXPathEvalPredicate:
14439 * @ctxt: the XPath context
14440 * @res: the Predicate Expression evaluation result
14441 *
14442 * Evaluate a predicate result for the current node.
14443 * A PredicateExpr is evaluated by evaluating the Expr and converting
14444 * the result to a boolean. If the result is a number, the result will
14445 * be converted to true if the number is equal to the position of the
14446 * context node in the context node list (as returned by the position
14447 * function) and will be converted to false otherwise; if the result
14448 * is not a number, then the result will be converted as if by a call
Daniel Veillard45490ae2008-07-29 09:13:19 +000014449 * to the boolean function.
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014450 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014451 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014452 */
14453int
14454xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014455 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014456 switch (res->type) {
14457 case XPATH_BOOLEAN:
14458 return(res->boolval);
14459 case XPATH_NUMBER:
14460 return(res->floatval == ctxt->proximityPosition);
14461 case XPATH_NODESET:
14462 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000014463 if (res->nodesetval == NULL)
14464 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014465 return(res->nodesetval->nodeNr != 0);
14466 case XPATH_STRING:
14467 return((res->stringval != NULL) &&
14468 (xmlStrlen(res->stringval) != 0));
14469 default:
14470 STRANGE
14471 }
14472 return(0);
14473}
14474
14475/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014476 * xmlXPathEvaluatePredicateResult:
14477 * @ctxt: the XPath Parser context
14478 * @res: the Predicate Expression evaluation result
14479 *
14480 * Evaluate a predicate result for the current node.
14481 * A PredicateExpr is evaluated by evaluating the Expr and converting
14482 * the result to a boolean. If the result is a number, the result will
14483 * be converted to true if the number is equal to the position of the
14484 * context node in the context node list (as returned by the position
14485 * function) and will be converted to false otherwise; if the result
14486 * is not a number, then the result will be converted as if by a call
Daniel Veillard45490ae2008-07-29 09:13:19 +000014487 * to the boolean function.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014488 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014489 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014490 */
14491int
Daniel Veillard45490ae2008-07-29 09:13:19 +000014492xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014493 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014494 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014495 switch (res->type) {
14496 case XPATH_BOOLEAN:
14497 return(res->boolval);
14498 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000014499#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000014500 return((res->floatval == ctxt->context->proximityPosition) &&
14501 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000014502#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014503 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000014504#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014505 case XPATH_NODESET:
14506 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000014507 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000014508 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014509 return(res->nodesetval->nodeNr != 0);
14510 case XPATH_STRING:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014511 return((res->stringval != NULL) && (res->stringval[0] != 0));
William M. Brack08171912003-12-29 02:52:11 +000014512#ifdef LIBXML_XPTR_ENABLED
14513 case XPATH_LOCATIONSET:{
14514 xmlLocationSetPtr ptr = res->user;
14515 if (ptr == NULL)
14516 return(0);
14517 return (ptr->locNr != 0);
14518 }
14519#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014520 default:
14521 STRANGE
14522 }
14523 return(0);
14524}
14525
Daniel Veillard56de87e2005-02-16 00:22:29 +000014526#ifdef XPATH_STREAMING
14527/**
14528 * xmlXPathTryStreamCompile:
14529 * @ctxt: an XPath context
14530 * @str: the XPath expression
14531 *
14532 * Try to compile the XPath expression as a streamable subset.
14533 *
14534 * Returns the compiled expression or NULL if failed to compile.
14535 */
14536static xmlXPathCompExprPtr
14537xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14538 /*
14539 * Optimization: use streaming patterns when the XPath expression can
14540 * be compiled to a stream lookup
14541 */
14542 xmlPatternPtr stream;
14543 xmlXPathCompExprPtr comp;
14544 xmlDictPtr dict = NULL;
14545 const xmlChar **namespaces = NULL;
14546 xmlNsPtr ns;
14547 int i, j;
14548
14549 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14550 (!xmlStrchr(str, '@'))) {
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014551 const xmlChar *tmp;
14552
14553 /*
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014554 * We don't try to handle expressions using the verbose axis
14555 * specifiers ("::"), just the simplied form at this point.
14556 * Additionally, if there is no list of namespaces available and
14557 * there's a ":" in the expression, indicating a prefixed QName,
14558 * then we won't try to compile either. xmlPatterncompile() needs
14559 * to have a list of namespaces at compilation time in order to
14560 * compile prefixed name tests.
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014561 */
14562 tmp = xmlStrchr(str, ':');
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014563 if ((tmp != NULL) &&
14564 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
Daniel Veillard45490ae2008-07-29 09:13:19 +000014565 return(NULL);
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014566
Daniel Veillard56de87e2005-02-16 00:22:29 +000014567 if (ctxt != NULL) {
14568 dict = ctxt->dict;
14569 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000014570 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000014571 if (namespaces == NULL) {
14572 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14573 return(NULL);
14574 }
14575 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14576 ns = ctxt->namespaces[j];
14577 namespaces[i++] = ns->href;
14578 namespaces[i++] = ns->prefix;
14579 }
14580 namespaces[i++] = NULL;
Daniel Veillard13cee4e2009-09-05 14:52:55 +020014581 namespaces[i] = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014582 }
14583 }
14584
William M. Brackea152c02005-06-09 18:12:28 +000014585 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14586 &namespaces[0]);
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014587 if (namespaces != NULL) {
14588 xmlFree((xmlChar **)namespaces);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014589 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014590 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14591 comp = xmlXPathNewCompExpr();
14592 if (comp == NULL) {
14593 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14594 return(NULL);
14595 }
14596 comp->stream = stream;
14597 comp->dict = dict;
14598 if (comp->dict)
14599 xmlDictReference(comp->dict);
14600 return(comp);
14601 }
14602 xmlFreePattern(stream);
14603 }
14604 return(NULL);
14605}
14606#endif /* XPATH_STREAMING */
14607
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014608static void
Nick Wellnhofer62270532012-08-19 19:42:38 +020014609xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014610{
14611 /*
14612 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14613 * internal representation.
14614 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014615
Nick Wellnhofer62270532012-08-19 19:42:38 +020014616 if ((op->ch1 != -1) &&
14617 (op->op == XPATH_OP_COLLECT /* 11 */))
14618 {
14619 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14620
14621 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14622 ((xmlXPathAxisVal) prevop->value ==
14623 AXIS_DESCENDANT_OR_SELF) &&
14624 (prevop->ch2 == -1) &&
14625 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14626 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14627 {
14628 /*
14629 * This is a "descendant-or-self::node()" without predicates.
14630 * Try to eliminate it.
14631 */
14632
14633 switch ((xmlXPathAxisVal) op->value) {
14634 case AXIS_CHILD:
14635 case AXIS_DESCENDANT:
14636 /*
14637 * Convert "descendant-or-self::node()/child::" or
14638 * "descendant-or-self::node()/descendant::" to
14639 * "descendant::"
14640 */
14641 op->ch1 = prevop->ch1;
14642 op->value = AXIS_DESCENDANT;
14643 break;
14644 case AXIS_SELF:
14645 case AXIS_DESCENDANT_OR_SELF:
14646 /*
14647 * Convert "descendant-or-self::node()/self::" or
14648 * "descendant-or-self::node()/descendant-or-self::" to
14649 * to "descendant-or-self::"
14650 */
14651 op->ch1 = prevop->ch1;
14652 op->value = AXIS_DESCENDANT_OR_SELF;
14653 break;
14654 default:
14655 break;
14656 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014657 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014658 }
Nick Wellnhofer62270532012-08-19 19:42:38 +020014659
14660 /* Recurse */
14661 if (op->ch1 != -1)
14662 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014663 if (op->ch2 != -1)
Nick Wellnhofer62270532012-08-19 19:42:38 +020014664 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014665}
14666
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014667/**
Daniel Veillard4773df22004-01-23 13:15:13 +000014668 * xmlXPathCtxtCompile:
14669 * @ctxt: an XPath context
14670 * @str: the XPath expression
14671 *
14672 * Compile an XPath expression
14673 *
14674 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14675 * the caller has to free the object.
14676 */
14677xmlXPathCompExprPtr
14678xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14679 xmlXPathParserContextPtr pctxt;
14680 xmlXPathCompExprPtr comp;
14681
Daniel Veillard56de87e2005-02-16 00:22:29 +000014682#ifdef XPATH_STREAMING
14683 comp = xmlXPathTryStreamCompile(ctxt, str);
14684 if (comp != NULL)
14685 return(comp);
14686#endif
14687
Daniel Veillard4773df22004-01-23 13:15:13 +000014688 xmlXPathInit();
14689
14690 pctxt = xmlXPathNewParserContext(str, ctxt);
William M. Brack11be2d02007-01-24 19:17:19 +000014691 if (pctxt == NULL)
14692 return NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014693 xmlXPathCompileExpr(pctxt, 1);
Daniel Veillard4773df22004-01-23 13:15:13 +000014694
14695 if( pctxt->error != XPATH_EXPRESSION_OK )
14696 {
14697 xmlXPathFreeParserContext(pctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000014698 return(NULL);
Daniel Veillard4773df22004-01-23 13:15:13 +000014699 }
14700
14701 if (*pctxt->cur != 0) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014702 /*
Daniel Veillard4773df22004-01-23 13:15:13 +000014703 * aleksey: in some cases this line prints *second* error message
14704 * (see bug #78858) and probably this should be fixed.
14705 * However, we are not sure that all error messages are printed
14706 * out in other places. It's not critical so we leave it as-is for now
14707 */
14708 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14709 comp = NULL;
14710 } else {
14711 comp = pctxt->comp;
14712 pctxt->comp = NULL;
14713 }
14714 xmlXPathFreeParserContext(pctxt);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014715
Daniel Veillard4773df22004-01-23 13:15:13 +000014716 if (comp != NULL) {
14717 comp->expr = xmlStrdup(str);
14718#ifdef DEBUG_EVAL_COUNTS
14719 comp->string = xmlStrdup(str);
14720 comp->nb = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014721#endif
Nick Wellnhofer62270532012-08-19 19:42:38 +020014722 if ((comp->nbStep > 1) && (comp->last >= 0)) {
14723 xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014724 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014725 }
Daniel Veillard4773df22004-01-23 13:15:13 +000014726 return(comp);
14727}
14728
14729/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014730 * xmlXPathCompile:
14731 * @str: the XPath expression
14732 *
14733 * Compile an XPath expression
14734 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000014735 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014736 * the caller has to free the object.
14737 */
14738xmlXPathCompExprPtr
14739xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000014740 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014741}
14742
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014743/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014744 * xmlXPathCompiledEvalInternal:
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014745 * @comp: the compiled XPath expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014746 * @ctxt: the XPath context
14747 * @resObj: the resulting XPath object or NULL
14748 * @toBool: 1 if only a boolean result is requested
Owen Taylor3473f882001-02-23 17:55:21 +000014749 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014750 * Evaluate the Precompiled XPath expression in the given context.
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014751 * The caller has to free @resObj.
Owen Taylor3473f882001-02-23 17:55:21 +000014752 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014753 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000014754 * the caller has to free the object.
14755 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014756static int
14757xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14758 xmlXPathContextPtr ctxt,
14759 xmlXPathObjectPtr *resObj,
14760 int toBool)
14761{
Daniel Veillard45490ae2008-07-29 09:13:19 +000014762 xmlXPathParserContextPtr pctxt;
Daniel Veillard81463942001-10-16 12:34:39 +000014763#ifndef LIBXML_THREAD_ENABLED
14764 static int reentance = 0;
14765#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014766 int res;
Owen Taylor3473f882001-02-23 17:55:21 +000014767
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014768 CHECK_CTXT_NEG(ctxt)
William M. Brackf13f77f2004-11-12 16:03:48 +000014769
14770 if (comp == NULL)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014771 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +000014772 xmlXPathInit();
14773
Daniel Veillard81463942001-10-16 12:34:39 +000014774#ifndef LIBXML_THREAD_ENABLED
14775 reentance++;
14776 if (reentance > 1)
14777 xmlXPathDisableOptimizer = 1;
14778#endif
14779
Daniel Veillardf06307e2001-07-03 10:35:50 +000014780#ifdef DEBUG_EVAL_COUNTS
14781 comp->nb++;
14782 if ((comp->string != NULL) && (comp->nb > 100)) {
14783 fprintf(stderr, "100 x %s\n", comp->string);
14784 comp->nb = 0;
14785 }
14786#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014787 pctxt = xmlXPathCompParserContext(comp, ctxt);
14788 res = xmlXPathRunEval(pctxt, toBool);
Owen Taylor3473f882001-02-23 17:55:21 +000014789
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014790 if (resObj) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014791 if (pctxt->value == NULL) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014792 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014793 "xmlXPathCompiledEval: evaluation failed\n");
Daniel Veillard45490ae2008-07-29 09:13:19 +000014794 *resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014795 } else {
14796 *resObj = valuePop(pctxt);
14797 }
Owen Taylor3473f882001-02-23 17:55:21 +000014798 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014799
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014800 /*
14801 * Pop all remaining objects from the stack.
14802 */
14803 if (pctxt->valueNr > 0) {
14804 xmlXPathObjectPtr tmp;
14805 int stack = 0;
14806
14807 do {
14808 tmp = valuePop(pctxt);
14809 if (tmp != NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014810 stack++;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014811 xmlXPathReleaseObject(ctxt, tmp);
14812 }
14813 } while (tmp != NULL);
14814 if ((stack != 0) &&
14815 ((toBool) || ((resObj) && (*resObj))))
14816 {
14817 xmlGenericError(xmlGenericErrorContext,
14818 "xmlXPathCompiledEval: %d objects left on the stack.\n",
14819 stack);
14820 }
Owen Taylor3473f882001-02-23 17:55:21 +000014821 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014822
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014823 if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14824 xmlXPathFreeObject(*resObj);
14825 *resObj = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014826 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014827 pctxt->comp = NULL;
14828 xmlXPathFreeParserContext(pctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000014829#ifndef LIBXML_THREAD_ENABLED
14830 reentance--;
14831#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014832
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014833 return(res);
14834}
14835
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014836/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014837 * xmlXPathCompiledEval:
14838 * @comp: the compiled XPath expression
14839 * @ctx: the XPath context
14840 *
14841 * Evaluate the Precompiled XPath expression in the given context.
14842 *
14843 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14844 * the caller has to free the object.
14845 */
14846xmlXPathObjectPtr
14847xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14848{
14849 xmlXPathObjectPtr res = NULL;
14850
14851 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14852 return(res);
14853}
14854
14855/**
14856 * xmlXPathCompiledEvalToBoolean:
14857 * @comp: the compiled XPath expression
14858 * @ctxt: the XPath context
14859 *
14860 * Applies the XPath boolean() function on the result of the given
14861 * compiled expression.
14862 *
14863 * Returns 1 if the expression evaluated to true, 0 if to false and
14864 * -1 in API and internal errors.
14865 */
14866int
14867xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14868 xmlXPathContextPtr ctxt)
14869{
14870 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14871}
14872
14873/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014874 * xmlXPathEvalExpr:
14875 * @ctxt: the XPath Parser context
14876 *
14877 * Parse and evaluate an XPath expression in the given context,
14878 * then push the result on the context stack
14879 */
14880void
14881xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014882#ifdef XPATH_STREAMING
14883 xmlXPathCompExprPtr comp;
14884#endif
14885
Daniel Veillarda82b1822004-11-08 16:24:57 +000014886 if (ctxt == NULL) return;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014887
Daniel Veillard56de87e2005-02-16 00:22:29 +000014888#ifdef XPATH_STREAMING
14889 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14890 if (comp != NULL) {
14891 if (ctxt->comp != NULL)
14892 xmlXPathFreeCompExpr(ctxt->comp);
14893 ctxt->comp = comp;
14894 if (ctxt->cur != NULL)
14895 while (*ctxt->cur != 0) ctxt->cur++;
14896 } else
14897#endif
14898 {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014899 xmlXPathCompileExpr(ctxt, 1);
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014900 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
14901 (ctxt->comp != NULL) &&
Nick Wellnhofer62270532012-08-19 19:42:38 +020014902 (ctxt->comp->nbStep > 1) &&
14903 (ctxt->comp->last >= 0))
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014904 {
Nick Wellnhofer62270532012-08-19 19:42:38 +020014905 xmlXPathOptimizeExpression(ctxt->comp,
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014906 &ctxt->comp->steps[ctxt->comp->last]);
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014907 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014908 }
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000014909 CHECK_ERROR;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014910 xmlXPathRunEval(ctxt, 0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014911}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014912
14913/**
14914 * xmlXPathEval:
14915 * @str: the XPath expression
14916 * @ctx: the XPath context
14917 *
14918 * Evaluate the XPath Location Path in the given context.
14919 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014920 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014921 * the caller has to free the object.
14922 */
14923xmlXPathObjectPtr
14924xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14925 xmlXPathParserContextPtr ctxt;
14926 xmlXPathObjectPtr res, tmp, init = NULL;
14927 int stack = 0;
14928
William M. Brackf13f77f2004-11-12 16:03:48 +000014929 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014930
William M. Brackf13f77f2004-11-12 16:03:48 +000014931 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014932
14933 ctxt = xmlXPathNewParserContext(str, ctx);
William M. Brack11be2d02007-01-24 19:17:19 +000014934 if (ctxt == NULL)
14935 return NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014936 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014937
14938 if (ctxt->value == NULL) {
14939 xmlGenericError(xmlGenericErrorContext,
14940 "xmlXPathEval: evaluation failed\n");
14941 res = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014942 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
Daniel Veillard56de87e2005-02-16 00:22:29 +000014943#ifdef XPATH_STREAMING
14944 && (ctxt->comp->stream == NULL)
14945#endif
14946 ) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014947 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14948 res = NULL;
14949 } else {
14950 res = valuePop(ctxt);
14951 }
14952
14953 do {
14954 tmp = valuePop(ctxt);
14955 if (tmp != NULL) {
14956 if (tmp != init)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014957 stack++;
14958 xmlXPathReleaseObject(ctx, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014959 }
14960 } while (tmp != NULL);
14961 if ((stack != 0) && (res != NULL)) {
14962 xmlGenericError(xmlGenericErrorContext,
14963 "xmlXPathEval: %d object left on the stack\n",
14964 stack);
14965 }
14966 if (ctxt->error != XPATH_EXPRESSION_OK) {
14967 xmlXPathFreeObject(res);
14968 res = NULL;
14969 }
14970
Owen Taylor3473f882001-02-23 17:55:21 +000014971 xmlXPathFreeParserContext(ctxt);
14972 return(res);
14973}
14974
14975/**
14976 * xmlXPathEvalExpression:
14977 * @str: the XPath expression
14978 * @ctxt: the XPath context
14979 *
14980 * Evaluate the XPath expression in the given context.
14981 *
14982 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14983 * the caller has to free the object.
14984 */
14985xmlXPathObjectPtr
14986xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14987 xmlXPathParserContextPtr pctxt;
14988 xmlXPathObjectPtr res, tmp;
14989 int stack = 0;
14990
William M. Brackf13f77f2004-11-12 16:03:48 +000014991 CHECK_CTXT(ctxt)
Owen Taylor3473f882001-02-23 17:55:21 +000014992
William M. Brackf13f77f2004-11-12 16:03:48 +000014993 xmlXPathInit();
Owen Taylor3473f882001-02-23 17:55:21 +000014994
14995 pctxt = xmlXPathNewParserContext(str, ctxt);
William M. Brack11be2d02007-01-24 19:17:19 +000014996 if (pctxt == NULL)
14997 return NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000014998 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000014999
Daniel Veillardc465ffc2006-10-17 19:39:33 +000015000 if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
Owen Taylor3473f882001-02-23 17:55:21 +000015001 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
15002 res = NULL;
15003 } else {
15004 res = valuePop(pctxt);
15005 }
15006 do {
15007 tmp = valuePop(pctxt);
15008 if (tmp != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015009 xmlXPathReleaseObject(ctxt, tmp);
Owen Taylor3473f882001-02-23 17:55:21 +000015010 stack++;
15011 }
15012 } while (tmp != NULL);
15013 if ((stack != 0) && (res != NULL)) {
15014 xmlGenericError(xmlGenericErrorContext,
15015 "xmlXPathEvalExpression: %d object left on the stack\n",
15016 stack);
15017 }
15018 xmlXPathFreeParserContext(pctxt);
15019 return(res);
15020}
15021
Daniel Veillard42766c02002-08-22 20:52:17 +000015022/************************************************************************
15023 * *
15024 * Extra functions not pertaining to the XPath spec *
15025 * *
15026 ************************************************************************/
15027/**
15028 * xmlXPathEscapeUriFunction:
15029 * @ctxt: the XPath Parser context
15030 * @nargs: the number of arguments
15031 *
15032 * Implement the escape-uri() XPath function
15033 * string escape-uri(string $str, bool $escape-reserved)
15034 *
15035 * This function applies the URI escaping rules defined in section 2 of [RFC
15036 * 2396] to the string supplied as $uri-part, which typically represents all
15037 * or part of a URI. The effect of the function is to replace any special
15038 * character in the string by an escape sequence of the form %xx%yy...,
15039 * where xxyy... is the hexadecimal representation of the octets used to
15040 * represent the character in UTF-8.
15041 *
15042 * The set of characters that are escaped depends on the setting of the
15043 * boolean argument $escape-reserved.
15044 *
15045 * If $escape-reserved is true, all characters are escaped other than lower
15046 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15047 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15048 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15049 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15050 * A-F).
15051 *
15052 * If $escape-reserved is false, the behavior differs in that characters
15053 * referred to in [RFC 2396] as reserved characters are not escaped. These
15054 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
Daniel Veillard45490ae2008-07-29 09:13:19 +000015055 *
Daniel Veillard42766c02002-08-22 20:52:17 +000015056 * [RFC 2396] does not define whether escaped URIs should use lower case or
15057 * upper case for hexadecimal digits. To ensure that escaped URIs can be
15058 * compared using string comparison functions, this function must always use
15059 * the upper-case letters A-F.
Daniel Veillard45490ae2008-07-29 09:13:19 +000015060 *
Daniel Veillard42766c02002-08-22 20:52:17 +000015061 * Generally, $escape-reserved should be set to true when escaping a string
15062 * that is to form a single part of a URI, and to false when escaping an
15063 * entire URI or URI reference.
Daniel Veillard45490ae2008-07-29 09:13:19 +000015064 *
15065 * In the case of non-ascii characters, the string is encoded according to
Daniel Veillard42766c02002-08-22 20:52:17 +000015066 * utf-8 and then converted according to RFC 2396.
15067 *
15068 * Examples
Daniel Veillard45490ae2008-07-29 09:13:19 +000015069 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
Daniel Veillard42766c02002-08-22 20:52:17 +000015070 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15071 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15072 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15073 *
15074 */
Daniel Veillard118aed72002-09-24 14:13:13 +000015075static void
Daniel Veillard42766c02002-08-22 20:52:17 +000015076xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15077 xmlXPathObjectPtr str;
15078 int escape_reserved;
Daniel Veillardade10f22012-07-12 09:43:27 +080015079 xmlBufPtr target;
Daniel Veillard42766c02002-08-22 20:52:17 +000015080 xmlChar *cptr;
15081 xmlChar escape[4];
Daniel Veillard45490ae2008-07-29 09:13:19 +000015082
Daniel Veillard42766c02002-08-22 20:52:17 +000015083 CHECK_ARITY(2);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015084
Daniel Veillard42766c02002-08-22 20:52:17 +000015085 escape_reserved = xmlXPathPopBoolean(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015086
Daniel Veillard42766c02002-08-22 20:52:17 +000015087 CAST_TO_STRING;
15088 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015089
Daniel Veillardade10f22012-07-12 09:43:27 +080015090 target = xmlBufCreate();
Daniel Veillard45490ae2008-07-29 09:13:19 +000015091
Daniel Veillard42766c02002-08-22 20:52:17 +000015092 escape[0] = '%';
15093 escape[3] = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000015094
Daniel Veillard42766c02002-08-22 20:52:17 +000015095 if (target) {
15096 for (cptr = str->stringval; *cptr; cptr++) {
15097 if ((*cptr >= 'A' && *cptr <= 'Z') ||
15098 (*cptr >= 'a' && *cptr <= 'z') ||
15099 (*cptr >= '0' && *cptr <= '9') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000015100 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
Daniel Veillard42766c02002-08-22 20:52:17 +000015101 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
15102 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000015103 (*cptr == '%' &&
Daniel Veillard42766c02002-08-22 20:52:17 +000015104 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15105 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15106 (cptr[1] >= '0' && cptr[1] <= '9')) &&
15107 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15108 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15109 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15110 (!escape_reserved &&
15111 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15112 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15113 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15114 *cptr == ','))) {
Daniel Veillardade10f22012-07-12 09:43:27 +080015115 xmlBufAdd(target, cptr, 1);
Daniel Veillard42766c02002-08-22 20:52:17 +000015116 } else {
15117 if ((*cptr >> 4) < 10)
15118 escape[1] = '0' + (*cptr >> 4);
15119 else
15120 escape[1] = 'A' - 10 + (*cptr >> 4);
15121 if ((*cptr & 0xF) < 10)
15122 escape[2] = '0' + (*cptr & 0xF);
15123 else
15124 escape[2] = 'A' - 10 + (*cptr & 0xF);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015125
Daniel Veillardade10f22012-07-12 09:43:27 +080015126 xmlBufAdd(target, &escape[0], 3);
Daniel Veillard42766c02002-08-22 20:52:17 +000015127 }
15128 }
15129 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015130 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +080015131 xmlBufContent(target)));
15132 xmlBufFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015133 xmlXPathReleaseObject(ctxt->context, str);
Daniel Veillard42766c02002-08-22 20:52:17 +000015134}
15135
Owen Taylor3473f882001-02-23 17:55:21 +000015136/**
15137 * xmlXPathRegisterAllFunctions:
15138 * @ctxt: the XPath context
15139 *
15140 * Registers all default XPath functions in this context
15141 */
15142void
15143xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15144{
15145 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15146 xmlXPathBooleanFunction);
15147 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15148 xmlXPathCeilingFunction);
15149 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15150 xmlXPathCountFunction);
15151 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15152 xmlXPathConcatFunction);
15153 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15154 xmlXPathContainsFunction);
15155 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15156 xmlXPathIdFunction);
15157 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15158 xmlXPathFalseFunction);
15159 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15160 xmlXPathFloorFunction);
15161 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15162 xmlXPathLastFunction);
15163 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15164 xmlXPathLangFunction);
15165 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15166 xmlXPathLocalNameFunction);
15167 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15168 xmlXPathNotFunction);
15169 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15170 xmlXPathNameFunction);
15171 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15172 xmlXPathNamespaceURIFunction);
15173 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15174 xmlXPathNormalizeFunction);
15175 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15176 xmlXPathNumberFunction);
15177 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15178 xmlXPathPositionFunction);
15179 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15180 xmlXPathRoundFunction);
15181 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15182 xmlXPathStringFunction);
15183 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15184 xmlXPathStringLengthFunction);
15185 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15186 xmlXPathStartsWithFunction);
15187 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15188 xmlXPathSubstringFunction);
15189 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15190 xmlXPathSubstringBeforeFunction);
15191 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15192 xmlXPathSubstringAfterFunction);
15193 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15194 xmlXPathSumFunction);
15195 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15196 xmlXPathTrueFunction);
15197 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15198 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000015199
15200 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15201 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15202 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000015203}
15204
15205#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000015206#define bottom_xpath
15207#include "elfgcchack.h"