blob: d9d902c0a280b9635f14c764d67031e6e62dbddb [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
58#ifdef LIBXML_PATTERN_ENABLED
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000059#define XPATH_STREAMING
Daniel Veillard56de87e2005-02-16 00:22:29 +000060#endif
Owen Taylor3473f882001-02-23 17:55:21 +000061
Daniel Veillard45490ae2008-07-29 09:13:19 +000062#define TODO \
Daniel Veillardd96f6d32003-10-07 21:25:12 +000063 xmlGenericError(xmlGenericErrorContext, \
64 "Unimplemented block at %s:%d\n", \
65 __FILE__, __LINE__);
66
William M. Brackd1757ab2004-10-02 22:07:48 +000067/*
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000068* XP_OPTIMIZED_NON_ELEM_COMPARISON:
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +000069* If defined, this will use xmlXPathCmpNodesExt() instead of
70* xmlXPathCmpNodes(). The new function is optimized comparison of
71* non-element nodes; actually it will speed up comparison only if
72* xmlXPathOrderDocElems() was called in order to index the elements of
73* a tree in document order; Libxslt does such an indexing, thus it will
74* benefit from this optimization.
75*/
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000076#define XP_OPTIMIZED_NON_ELEM_COMPARISON
77
78/*
79* XP_OPTIMIZED_FILTER_FIRST:
80* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
81* in a way, that it stop evaluation at the first node.
Daniel Veillard45490ae2008-07-29 09:13:19 +000082*/
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000083#define XP_OPTIMIZED_FILTER_FIRST
84
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000085/*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000086* XP_DEBUG_OBJ_USAGE:
87* Internal flag to enable tracking of how much XPath objects have been
88* created.
89*/
90/* #define XP_DEBUG_OBJ_USAGE */
91
92/*
William M. Brackd1757ab2004-10-02 22:07:48 +000093 * TODO:
94 * There are a few spots where some tests are done which depend upon ascii
95 * data. These should be enhanced for full UTF8 support (see particularly
96 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
97 */
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000098
William M. Brack21e4ef22005-01-02 09:53:13 +000099#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000100
101/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000102 * *
103 * Floating point stuff *
104 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000105 ************************************************************************/
106
Daniel Veillardc0631a62001-09-20 13:56:06 +0000107#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +0000108#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +0000109#endif
Daniel Veillardcda96922001-08-21 10:56:31 +0000110#include "trionan.c"
111
Owen Taylor3473f882001-02-23 17:55:21 +0000112/*
Owen Taylor3473f882001-02-23 17:55:21 +0000113 * The lack of portability of this section of the libc is annoying !
114 */
115double xmlXPathNAN = 0;
116double xmlXPathPINF = 1;
117double xmlXPathNINF = -1;
Daniel Veillard24505b02005-07-28 23:49:35 +0000118static double xmlXPathNZERO = 0; /* not exported from headers */
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000119static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000120
Owen Taylor3473f882001-02-23 17:55:21 +0000121/**
122 * xmlXPathInit:
123 *
124 * Initialize the XPath environment
125 */
126void
127xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000128 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +0000129
Bjorn Reese45029602001-08-21 09:23:53 +0000130 xmlXPathPINF = trio_pinf();
131 xmlXPathNINF = trio_ninf();
132 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000133 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +0000134
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000135 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000136}
137
Daniel Veillardcda96922001-08-21 10:56:31 +0000138/**
139 * xmlXPathIsNaN:
140 * @val: a double value
141 *
142 * Provides a portable isnan() function to detect whether a double
143 * is a NotaNumber. Based on trio code
144 * http://sourceforge.net/projects/ctrio/
Daniel Veillard45490ae2008-07-29 09:13:19 +0000145 *
Daniel Veillardcda96922001-08-21 10:56:31 +0000146 * Returns 1 if the value is a NaN, 0 otherwise
147 */
148int
149xmlXPathIsNaN(double val) {
150 return(trio_isnan(val));
151}
152
153/**
154 * xmlXPathIsInf:
155 * @val: a double value
156 *
157 * Provides a portable isinf() function to detect whether a double
158 * is a +Infinite or -Infinite. Based on trio code
159 * http://sourceforge.net/projects/ctrio/
Daniel Veillard45490ae2008-07-29 09:13:19 +0000160 *
Daniel Veillardcda96922001-08-21 10:56:31 +0000161 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
162 */
163int
164xmlXPathIsInf(double val) {
165 return(trio_isinf(val));
166}
167
Daniel Veillard4432df22003-09-28 18:58:27 +0000168#endif /* SCHEMAS or XPATH */
169#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000170/**
171 * xmlXPathGetSign:
172 * @val: a double value
173 *
174 * Provides a portable function to detect the sign of a double
175 * Modified from trio code
176 * http://sourceforge.net/projects/ctrio/
Daniel Veillard45490ae2008-07-29 09:13:19 +0000177 *
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000178 * Returns 1 if the value is Negative, 0 if positive
179 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000180static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000181xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000182 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000183}
184
185
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000186/*
187 * TODO: when compatibility allows remove all "fake node libxslt" strings
188 * the test should just be name[0] = ' '
189 */
Daniel Veillard074f37e2008-09-01 13:38:22 +0000190#ifdef DEBUG_XPATH_EXPRESSION
191#define DEBUG_STEP
192#define DEBUG_EXPR
193#define DEBUG_EVAL_COUNTS
194#endif
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000195
196static xmlNs xmlXPathXMLNamespaceStruct = {
197 NULL,
198 XML_NAMESPACE_DECL,
199 XML_XML_NAMESPACE,
200 BAD_CAST "xml",
William M. Brackee0b9822007-03-07 08:15:01 +0000201 NULL,
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000202 NULL
203};
204static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
205#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard45490ae2008-07-29 09:13:19 +0000206/*
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000207 * Optimizer is disabled only when threaded apps are detected while
208 * the library ain't compiled for thread safety.
209 */
210static int xmlXPathDisableOptimizer = 0;
211#endif
212
Owen Taylor3473f882001-02-23 17:55:21 +0000213/************************************************************************
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000214 * *
215 * Error handling routines *
216 * *
217 ************************************************************************/
218
Daniel Veillard24505b02005-07-28 23:49:35 +0000219/**
220 * XP_ERRORNULL:
221 * @X: the error code
222 *
223 * Macro to raise an XPath error and return NULL.
224 */
225#define XP_ERRORNULL(X) \
226 { xmlXPathErr(ctxt, X); return(NULL); }
227
William M. Brack08171912003-12-29 02:52:11 +0000228/*
229 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
230 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000231static const char *xmlXPathErrorMessages[] = {
232 "Ok\n",
233 "Number encoding\n",
234 "Unfinished literal\n",
235 "Start of literal\n",
236 "Expected $ for variable reference\n",
237 "Undefined variable\n",
238 "Invalid predicate\n",
239 "Invalid expression\n",
240 "Missing closing curly brace\n",
241 "Unregistered function\n",
242 "Invalid operand\n",
243 "Invalid type\n",
244 "Invalid number of arguments\n",
245 "Invalid context size\n",
246 "Invalid context position\n",
247 "Memory allocation error\n",
248 "Syntax error\n",
249 "Resource error\n",
250 "Sub resource error\n",
251 "Undefined namespace prefix\n",
252 "Encoding error\n",
Daniel Veillard57b25162004-11-06 14:50:18 +0000253 "Char out of XML range\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000254 "Invalid or incomplete context\n",
Daniel Veillardf5048b32011-08-18 17:10:13 +0800255 "Stack usage errror\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000256 "?? Unknown error ??\n" /* Must be last in the list! */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000257};
William M. Brackcd65bc92005-01-06 09:39:18 +0000258#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
259 sizeof(xmlXPathErrorMessages[0])) - 1)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000260/**
261 * xmlXPathErrMemory:
262 * @ctxt: an XPath context
263 * @extra: extra informations
264 *
265 * Handle a redefinition of attribute error
266 */
267static void
268xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
269{
270 if (ctxt != NULL) {
271 if (extra) {
272 xmlChar buf[200];
273
274 xmlStrPrintf(buf, 200,
275 BAD_CAST "Memory allocation failed : %s\n",
276 extra);
277 ctxt->lastError.message = (char *) xmlStrdup(buf);
278 } else {
279 ctxt->lastError.message = (char *)
280 xmlStrdup(BAD_CAST "Memory allocation failed\n");
281 }
282 ctxt->lastError.domain = XML_FROM_XPATH;
283 ctxt->lastError.code = XML_ERR_NO_MEMORY;
284 if (ctxt->error != NULL)
285 ctxt->error(ctxt->userData, &ctxt->lastError);
286 } else {
287 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000288 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000289 NULL, NULL, XML_FROM_XPATH,
290 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
291 extra, NULL, NULL, 0, 0,
292 "Memory allocation failed : %s\n", extra);
293 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000294 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000295 NULL, NULL, XML_FROM_XPATH,
296 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
297 NULL, NULL, NULL, 0, 0,
298 "Memory allocation failed\n");
299 }
300}
301
302/**
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000303 * xmlXPathPErrMemory:
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000304 * @ctxt: an XPath parser context
305 * @extra: extra informations
306 *
307 * Handle a redefinition of attribute error
308 */
309static void
310xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
311{
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000312 if (ctxt == NULL)
313 xmlXPathErrMemory(NULL, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000314 else {
315 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000316 xmlXPathErrMemory(ctxt->context, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000317 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000318}
319
320/**
321 * xmlXPathErr:
322 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000323 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000324 *
William M. Brackcd65bc92005-01-06 09:39:18 +0000325 * Handle an XPath error
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000326 */
327void
328xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
329{
William M. Brackcd65bc92005-01-06 09:39:18 +0000330 if ((error < 0) || (error > MAXERRNO))
331 error = MAXERRNO;
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000332 if (ctxt == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000333 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000334 NULL, NULL, XML_FROM_XPATH,
335 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
336 XML_ERR_ERROR, NULL, 0,
337 NULL, NULL, NULL, 0, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200338 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000339 return;
340 }
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000341 ctxt->error = error;
342 if (ctxt->context == NULL) {
343 __xmlRaiseError(NULL, NULL, NULL,
344 NULL, NULL, XML_FROM_XPATH,
345 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
346 XML_ERR_ERROR, NULL, 0,
347 (const char *) ctxt->base, NULL, NULL,
348 ctxt->cur - ctxt->base, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200349 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000350 return;
351 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +0000352
353 /* cleanup current last error */
Daniel Veillard45490ae2008-07-29 09:13:19 +0000354 xmlResetError(&ctxt->context->lastError);
Aleksey Sanin1b2be102006-05-31 20:53:43 +0000355
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000356 ctxt->context->lastError.domain = XML_FROM_XPATH;
357 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
358 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000359 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000360 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
361 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
362 ctxt->context->lastError.node = ctxt->context->debugNode;
363 if (ctxt->context->error != NULL) {
364 ctxt->context->error(ctxt->context->userData,
365 &ctxt->context->lastError);
366 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000367 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000368 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
369 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
370 XML_ERR_ERROR, NULL, 0,
371 (const char *) ctxt->base, NULL, NULL,
372 ctxt->cur - ctxt->base, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200373 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000374 }
375
376}
377
378/**
379 * xmlXPatherror:
380 * @ctxt: the XPath Parser context
381 * @file: the file name
382 * @line: the line number
383 * @no: the error number
384 *
385 * Formats an error message.
386 */
387void
388xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
389 int line ATTRIBUTE_UNUSED, int no) {
390 xmlXPathErr(ctxt, no);
391}
392
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000393/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000394 * *
395 * Utilities *
396 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000397 ************************************************************************/
398
399/**
400 * xsltPointerList:
401 *
402 * Pointer-list for various purposes.
403 */
404typedef struct _xmlPointerList xmlPointerList;
405typedef xmlPointerList *xmlPointerListPtr;
406struct _xmlPointerList {
407 void **items;
408 int number;
409 int size;
410};
411/*
412* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
413* and here, we should make the functions public.
414*/
415static int
Daniel Veillard45490ae2008-07-29 09:13:19 +0000416xmlPointerListAddSize(xmlPointerListPtr list,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000417 void *item,
418 int initialSize)
419{
420 if (list->items == NULL) {
421 if (initialSize <= 0)
422 initialSize = 1;
423 list->items = (void **) xmlMalloc(
424 initialSize * sizeof(void *));
425 if (list->items == NULL) {
426 xmlXPathErrMemory(NULL,
427 "xmlPointerListCreate: allocating item\n");
428 return(-1);
429 }
430 list->number = 0;
431 list->size = initialSize;
432 } else if (list->size <= list->number) {
433 list->size *= 2;
434 list->items = (void **) xmlRealloc(list->items,
435 list->size * sizeof(void *));
436 if (list->items == NULL) {
437 xmlXPathErrMemory(NULL,
438 "xmlPointerListCreate: re-allocating item\n");
439 list->size = 0;
440 return(-1);
441 }
442 }
443 list->items[list->number++] = item;
444 return(0);
445}
446
447/**
448 * xsltPointerListCreate:
449 *
450 * Creates an xsltPointerList structure.
451 *
452 * Returns a xsltPointerList structure or NULL in case of an error.
453 */
454static xmlPointerListPtr
455xmlPointerListCreate(int initialSize)
456{
457 xmlPointerListPtr ret;
458
459 ret = xmlMalloc(sizeof(xmlPointerList));
460 if (ret == NULL) {
461 xmlXPathErrMemory(NULL,
462 "xmlPointerListCreate: allocating item\n");
463 return (NULL);
464 }
465 memset(ret, 0, sizeof(xmlPointerList));
466 if (initialSize > 0) {
467 xmlPointerListAddSize(ret, NULL, initialSize);
468 ret->number = 0;
469 }
470 return (ret);
471}
472
473/**
474 * xsltPointerListFree:
475 *
476 * Frees the xsltPointerList structure. This does not free
477 * the content of the list.
478 */
479static void
480xmlPointerListFree(xmlPointerListPtr list)
481{
482 if (list == NULL)
483 return;
484 if (list->items != NULL)
485 xmlFree(list->items);
486 xmlFree(list);
487}
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000488
489/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000490 * *
491 * Parser Types *
492 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000493 ************************************************************************/
494
495/*
496 * Types are private:
497 */
498
499typedef enum {
500 XPATH_OP_END=0,
501 XPATH_OP_AND,
502 XPATH_OP_OR,
503 XPATH_OP_EQUAL,
504 XPATH_OP_CMP,
505 XPATH_OP_PLUS,
506 XPATH_OP_MULT,
507 XPATH_OP_UNION,
508 XPATH_OP_ROOT,
509 XPATH_OP_NODE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000510 XPATH_OP_RESET, /* 10 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000511 XPATH_OP_COLLECT,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000512 XPATH_OP_VALUE, /* 12 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000513 XPATH_OP_VARIABLE,
514 XPATH_OP_FUNCTION,
515 XPATH_OP_ARG,
516 XPATH_OP_PREDICATE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000517 XPATH_OP_FILTER, /* 17 */
518 XPATH_OP_SORT /* 18 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000519#ifdef LIBXML_XPTR_ENABLED
520 ,XPATH_OP_RANGETO
521#endif
522} xmlXPathOp;
523
524typedef enum {
525 AXIS_ANCESTOR = 1,
526 AXIS_ANCESTOR_OR_SELF,
527 AXIS_ATTRIBUTE,
528 AXIS_CHILD,
529 AXIS_DESCENDANT,
530 AXIS_DESCENDANT_OR_SELF,
531 AXIS_FOLLOWING,
532 AXIS_FOLLOWING_SIBLING,
533 AXIS_NAMESPACE,
534 AXIS_PARENT,
535 AXIS_PRECEDING,
536 AXIS_PRECEDING_SIBLING,
Daniel Veillard45490ae2008-07-29 09:13:19 +0000537 AXIS_SELF
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000538} xmlXPathAxisVal;
539
540typedef enum {
541 NODE_TEST_NONE = 0,
542 NODE_TEST_TYPE = 1,
543 NODE_TEST_PI = 2,
544 NODE_TEST_ALL = 3,
545 NODE_TEST_NS = 4,
546 NODE_TEST_NAME = 5
547} xmlXPathTestVal;
548
549typedef enum {
550 NODE_TYPE_NODE = 0,
551 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
552 NODE_TYPE_TEXT = XML_TEXT_NODE,
Daniel Veillard45490ae2008-07-29 09:13:19 +0000553 NODE_TYPE_PI = XML_PI_NODE
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000554} xmlXPathTypeVal;
555
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +0000556#define XP_REWRITE_DOS_CHILD_ELEM 1
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000557
558typedef struct _xmlXPathStepOp xmlXPathStepOp;
559typedef xmlXPathStepOp *xmlXPathStepOpPtr;
560struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000561 xmlXPathOp op; /* The identifier of the operation */
562 int ch1; /* First child */
563 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000564 int value;
565 int value2;
566 int value3;
567 void *value4;
568 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000569 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000570 void *cacheURI;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +0000571 int rewriteType;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000572};
573
574struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000575 int nbStep; /* Number of steps in this expression */
576 int maxStep; /* Maximum number of steps allocated */
577 xmlXPathStepOp *steps; /* ops for computation of this expression */
578 int last; /* index of last step in expression */
579 xmlChar *expr; /* the expression being computed */
Daniel Veillard4773df22004-01-23 13:15:13 +0000580 xmlDictPtr dict; /* the dictionnary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000581#ifdef DEBUG_EVAL_COUNTS
582 int nb;
583 xmlChar *string;
584#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000585#ifdef XPATH_STREAMING
586 xmlPatternPtr stream;
587#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000588};
589
590/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000591 * *
592 * Forward declarations *
593 * *
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000594 ************************************************************************/
595static void
596xmlXPathFreeValueTree(xmlNodeSetPtr obj);
597static void
598xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
599static int
600xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
601 xmlXPathStepOpPtr op, xmlNodePtr *first);
602static int
603xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +0000604 xmlXPathStepOpPtr op,
605 int isPredicate);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000606
607/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000608 * *
609 * Parser Type functions *
610 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000611 ************************************************************************/
612
613/**
614 * xmlXPathNewCompExpr:
615 *
616 * Create a new Xpath component
617 *
618 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
619 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000620static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000621xmlXPathNewCompExpr(void) {
622 xmlXPathCompExprPtr cur;
623
624 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
625 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000626 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000627 return(NULL);
628 }
629 memset(cur, 0, sizeof(xmlXPathCompExpr));
630 cur->maxStep = 10;
631 cur->nbStep = 0;
632 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
633 sizeof(xmlXPathStepOp));
634 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000635 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000636 xmlFree(cur);
637 return(NULL);
638 }
639 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
640 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000641#ifdef DEBUG_EVAL_COUNTS
642 cur->nb = 0;
643#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000644 return(cur);
645}
646
647/**
648 * xmlXPathFreeCompExpr:
649 * @comp: an XPATH comp
650 *
651 * Free up the memory allocated by @comp
652 */
653void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000654xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
655{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000656 xmlXPathStepOpPtr op;
657 int i;
658
659 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000660 return;
Daniel Veillard4773df22004-01-23 13:15:13 +0000661 if (comp->dict == NULL) {
662 for (i = 0; i < comp->nbStep; i++) {
663 op = &comp->steps[i];
664 if (op->value4 != NULL) {
665 if (op->op == XPATH_OP_VALUE)
666 xmlXPathFreeObject(op->value4);
667 else
668 xmlFree(op->value4);
669 }
670 if (op->value5 != NULL)
671 xmlFree(op->value5);
672 }
673 } else {
674 for (i = 0; i < comp->nbStep; i++) {
675 op = &comp->steps[i];
676 if (op->value4 != NULL) {
677 if (op->op == XPATH_OP_VALUE)
678 xmlXPathFreeObject(op->value4);
679 }
680 }
681 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000682 }
683 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000684 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000685 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000686#ifdef DEBUG_EVAL_COUNTS
687 if (comp->string != NULL) {
688 xmlFree(comp->string);
689 }
690#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000691#ifdef XPATH_STREAMING
692 if (comp->stream != NULL) {
693 xmlFreePatternList(comp->stream);
694 }
695#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000696 if (comp->expr != NULL) {
697 xmlFree(comp->expr);
698 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000699
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000700 xmlFree(comp);
701}
702
703/**
704 * xmlXPathCompExprAdd:
705 * @comp: the compiled expression
706 * @ch1: first child index
707 * @ch2: second child index
708 * @op: an op
709 * @value: the first int value
710 * @value2: the second int value
711 * @value3: the third int value
712 * @value4: the first string value
713 * @value5: the second string value
714 *
William M. Brack08171912003-12-29 02:52:11 +0000715 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000716 *
717 * Returns -1 in case of failure, the index otherwise
718 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000719static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000720xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
721 xmlXPathOp op, int value,
722 int value2, int value3, void *value4, void *value5) {
723 if (comp->nbStep >= comp->maxStep) {
724 xmlXPathStepOp *real;
725
726 comp->maxStep *= 2;
727 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
728 comp->maxStep * sizeof(xmlXPathStepOp));
729 if (real == NULL) {
730 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000731 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000732 return(-1);
733 }
734 comp->steps = real;
735 }
736 comp->last = comp->nbStep;
Kasimier T. Buchcik6422d912006-06-26 14:31:53 +0000737 comp->steps[comp->nbStep].rewriteType = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000738 comp->steps[comp->nbStep].ch1 = ch1;
739 comp->steps[comp->nbStep].ch2 = ch2;
740 comp->steps[comp->nbStep].op = op;
741 comp->steps[comp->nbStep].value = value;
742 comp->steps[comp->nbStep].value2 = value2;
743 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +0000744 if ((comp->dict != NULL) &&
745 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
746 (op == XPATH_OP_COLLECT))) {
747 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000748 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000749 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000750 xmlFree(value4);
751 } else
752 comp->steps[comp->nbStep].value4 = NULL;
753 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000754 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000755 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000756 xmlFree(value5);
757 } else
758 comp->steps[comp->nbStep].value5 = NULL;
759 } else {
760 comp->steps[comp->nbStep].value4 = value4;
761 comp->steps[comp->nbStep].value5 = value5;
762 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000763 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000764 return(comp->nbStep++);
765}
766
Daniel Veillardf06307e2001-07-03 10:35:50 +0000767/**
768 * xmlXPathCompSwap:
769 * @comp: the compiled expression
770 * @op: operation index
771 *
772 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000773 */
774static void
775xmlXPathCompSwap(xmlXPathStepOpPtr op) {
776 int tmp;
777
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000778#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000779 /*
780 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +0000781 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +0000782 * application
783 */
784 if (xmlXPathDisableOptimizer)
785 return;
786#endif
787
Daniel Veillardf06307e2001-07-03 10:35:50 +0000788 tmp = op->ch1;
789 op->ch1 = op->ch2;
790 op->ch2 = tmp;
791}
792
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000793#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
794 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
795 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000796#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
797 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
798 (op), (val), (val2), (val3), (val4), (val5))
799
Daniel Veillard45490ae2008-07-29 09:13:19 +0000800#define PUSH_LEAVE_EXPR(op, val, val2) \
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000801xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
802
Daniel Veillard45490ae2008-07-29 09:13:19 +0000803#define PUSH_UNARY_EXPR(op, ch, val, val2) \
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000804xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
805
Daniel Veillard45490ae2008-07-29 09:13:19 +0000806#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +0000807xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
808 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000809
810/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000811 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +0000812 * XPath object cache structures *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000813 * *
814 ************************************************************************/
815
816/* #define XP_DEFAULT_CACHE_ON */
817
Kasimier T. Buchcik58694692006-05-31 12:37:28 +0000818#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000819
Kasimier T. Buchcik58694692006-05-31 12:37:28 +0000820typedef struct _xmlXPathContextCache xmlXPathContextCache;
821typedef xmlXPathContextCache *xmlXPathContextCachePtr;
822struct _xmlXPathContextCache {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +0000823 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
824 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
825 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
826 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
827 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000828 int maxNodeset;
829 int maxString;
830 int maxBoolean;
831 int maxNumber;
832 int maxMisc;
833#ifdef XP_DEBUG_OBJ_USAGE
834 int dbgCachedAll;
835 int dbgCachedNodeset;
836 int dbgCachedString;
837 int dbgCachedBool;
838 int dbgCachedNumber;
839 int dbgCachedPoint;
840 int dbgCachedRange;
841 int dbgCachedLocset;
842 int dbgCachedUsers;
843 int dbgCachedXSLTTree;
Daniel Veillard45490ae2008-07-29 09:13:19 +0000844 int dbgCachedUndefined;
845
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000846
847 int dbgReusedAll;
848 int dbgReusedNodeset;
849 int dbgReusedString;
850 int dbgReusedBool;
851 int dbgReusedNumber;
852 int dbgReusedPoint;
853 int dbgReusedRange;
854 int dbgReusedLocset;
855 int dbgReusedUsers;
856 int dbgReusedXSLTTree;
857 int dbgReusedUndefined;
858
859#endif
860};
861
862/************************************************************************
863 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +0000864 * Debugging related functions *
Owen Taylor3473f882001-02-23 17:55:21 +0000865 * *
866 ************************************************************************/
867
Daniel Veillard45490ae2008-07-29 09:13:19 +0000868#define STRANGE \
Owen Taylor3473f882001-02-23 17:55:21 +0000869 xmlGenericError(xmlGenericErrorContext, \
870 "Internal error at %s:%d\n", \
871 __FILE__, __LINE__);
872
873#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000874static void
875xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000876 int i;
877 char shift[100];
878
879 for (i = 0;((i < depth) && (i < 25));i++)
880 shift[2 * i] = shift[2 * i + 1] = ' ';
881 shift[2 * i] = shift[2 * i + 1] = 0;
882 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200883 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +0000884 fprintf(output, "Node is NULL !\n");
885 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +0000886
Owen Taylor3473f882001-02-23 17:55:21 +0000887 }
888
889 if ((cur->type == XML_DOCUMENT_NODE) ||
890 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200891 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +0000892 fprintf(output, " /\n");
893 } else if (cur->type == XML_ATTRIBUTE_NODE)
894 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
895 else
896 xmlDebugDumpOneNode(output, cur, depth);
897}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000898static void
899xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000900 xmlNodePtr tmp;
901 int i;
902 char shift[100];
903
904 for (i = 0;((i < depth) && (i < 25));i++)
905 shift[2 * i] = shift[2 * i + 1] = ' ';
906 shift[2 * i] = shift[2 * i + 1] = 0;
907 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200908 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000909 fprintf(output, "Node is NULL !\n");
910 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +0000911
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000912 }
913
914 while (cur != NULL) {
915 tmp = cur;
916 cur = cur->next;
917 xmlDebugDumpOneNode(output, tmp, depth);
918 }
919}
Owen Taylor3473f882001-02-23 17:55:21 +0000920
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000921static void
922xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000923 int i;
924 char shift[100];
925
926 for (i = 0;((i < depth) && (i < 25));i++)
927 shift[2 * i] = shift[2 * i + 1] = ' ';
928 shift[2 * i] = shift[2 * i + 1] = 0;
929
930 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200931 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +0000932 fprintf(output, "NodeSet is NULL !\n");
933 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +0000934
Owen Taylor3473f882001-02-23 17:55:21 +0000935 }
936
Daniel Veillard911f49a2001-04-07 15:39:35 +0000937 if (cur != NULL) {
938 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
939 for (i = 0;i < cur->nodeNr;i++) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200940 fprintf(output, "%s", shift);
Daniel Veillard911f49a2001-04-07 15:39:35 +0000941 fprintf(output, "%d", i + 1);
942 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
943 }
Owen Taylor3473f882001-02-23 17:55:21 +0000944 }
945}
946
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000947static void
948xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000949 int i;
950 char shift[100];
951
952 for (i = 0;((i < depth) && (i < 25));i++)
953 shift[2 * i] = shift[2 * i + 1] = ' ';
954 shift[2 * i] = shift[2 * i + 1] = 0;
955
956 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200957 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000958 fprintf(output, "Value Tree is NULL !\n");
959 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +0000960
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000961 }
962
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200963 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000964 fprintf(output, "%d", i + 1);
965 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
966}
Owen Taylor3473f882001-02-23 17:55:21 +0000967#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000968static void
969xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000970 int i;
971 char shift[100];
972
973 for (i = 0;((i < depth) && (i < 25));i++)
974 shift[2 * i] = shift[2 * i + 1] = ' ';
975 shift[2 * i] = shift[2 * i + 1] = 0;
976
977 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200978 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +0000979 fprintf(output, "LocationSet is NULL !\n");
980 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +0000981
Owen Taylor3473f882001-02-23 17:55:21 +0000982 }
983
984 for (i = 0;i < cur->locNr;i++) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200985 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +0000986 fprintf(output, "%d : ", i + 1);
987 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
988 }
989}
Daniel Veillard017b1082001-06-21 11:20:21 +0000990#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000991
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000992/**
993 * xmlXPathDebugDumpObject:
994 * @output: the FILE * to dump the output
995 * @cur: the object to inspect
996 * @depth: indentation level
997 *
998 * Dump the content of the object for debugging purposes
999 */
1000void
1001xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001002 int i;
1003 char shift[100];
1004
Daniel Veillarda82b1822004-11-08 16:24:57 +00001005 if (output == NULL) return;
1006
Owen Taylor3473f882001-02-23 17:55:21 +00001007 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
Kasimier T. Buchcik97258712006-01-05 12:30:43 +00001011
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001012 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001013
1014 if (cur == NULL) {
1015 fprintf(output, "Object is empty (NULL)\n");
1016 return;
1017 }
1018 switch(cur->type) {
1019 case XPATH_UNDEFINED:
1020 fprintf(output, "Object is uninitialized\n");
1021 break;
1022 case XPATH_NODESET:
1023 fprintf(output, "Object is a Node Set :\n");
1024 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1025 break;
1026 case XPATH_XSLT_TREE:
1027 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001028 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +00001029 break;
1030 case XPATH_BOOLEAN:
1031 fprintf(output, "Object is a Boolean : ");
1032 if (cur->boolval) fprintf(output, "true\n");
1033 else fprintf(output, "false\n");
1034 break;
1035 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +00001036 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001037 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001038 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001039 break;
1040 case -1:
1041 fprintf(output, "Object is a number : -Infinity\n");
1042 break;
1043 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001044 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001045 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001046 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1047 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001048 } else {
1049 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1050 }
1051 }
Owen Taylor3473f882001-02-23 17:55:21 +00001052 break;
1053 case XPATH_STRING:
1054 fprintf(output, "Object is a string : ");
1055 xmlDebugDumpString(output, cur->stringval);
1056 fprintf(output, "\n");
1057 break;
1058 case XPATH_POINT:
1059 fprintf(output, "Object is a point : index %d in node", cur->index);
1060 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1061 fprintf(output, "\n");
1062 break;
1063 case XPATH_RANGE:
1064 if ((cur->user2 == NULL) ||
1065 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1066 fprintf(output, "Object is a collapsed range :\n");
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001067 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001068 if (cur->index >= 0)
1069 fprintf(output, "index %d in ", cur->index);
1070 fprintf(output, "node\n");
1071 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1072 depth + 1);
1073 } else {
1074 fprintf(output, "Object is a range :\n");
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001075 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001076 fprintf(output, "From ");
1077 if (cur->index >= 0)
1078 fprintf(output, "index %d in ", cur->index);
1079 fprintf(output, "node\n");
1080 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1081 depth + 1);
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001082 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001083 fprintf(output, "To ");
1084 if (cur->index2 >= 0)
1085 fprintf(output, "index %d in ", cur->index2);
1086 fprintf(output, "node\n");
1087 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1088 depth + 1);
1089 fprintf(output, "\n");
1090 }
1091 break;
1092 case XPATH_LOCATIONSET:
1093#if defined(LIBXML_XPTR_ENABLED)
1094 fprintf(output, "Object is a Location Set:\n");
1095 xmlXPathDebugDumpLocationSet(output,
1096 (xmlLocationSetPtr) cur->user, depth);
1097#endif
1098 break;
1099 case XPATH_USERS:
1100 fprintf(output, "Object is user defined\n");
1101 break;
1102 }
1103}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001104
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001105static void
1106xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001107 xmlXPathStepOpPtr op, int depth) {
1108 int i;
1109 char shift[100];
1110
1111 for (i = 0;((i < depth) && (i < 25));i++)
1112 shift[2 * i] = shift[2 * i + 1] = ' ';
1113 shift[2 * i] = shift[2 * i + 1] = 0;
1114
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001115 fprintf(output, "%s", shift);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001116 if (op == NULL) {
1117 fprintf(output, "Step is NULL\n");
1118 return;
1119 }
1120 switch (op->op) {
1121 case XPATH_OP_END:
1122 fprintf(output, "END"); break;
1123 case XPATH_OP_AND:
1124 fprintf(output, "AND"); break;
1125 case XPATH_OP_OR:
1126 fprintf(output, "OR"); break;
1127 case XPATH_OP_EQUAL:
1128 if (op->value)
1129 fprintf(output, "EQUAL =");
1130 else
1131 fprintf(output, "EQUAL !=");
1132 break;
1133 case XPATH_OP_CMP:
1134 if (op->value)
1135 fprintf(output, "CMP <");
1136 else
1137 fprintf(output, "CMP >");
1138 if (!op->value2)
1139 fprintf(output, "=");
1140 break;
1141 case XPATH_OP_PLUS:
1142 if (op->value == 0)
1143 fprintf(output, "PLUS -");
1144 else if (op->value == 1)
1145 fprintf(output, "PLUS +");
1146 else if (op->value == 2)
1147 fprintf(output, "PLUS unary -");
1148 else if (op->value == 3)
1149 fprintf(output, "PLUS unary - -");
1150 break;
1151 case XPATH_OP_MULT:
1152 if (op->value == 0)
1153 fprintf(output, "MULT *");
1154 else if (op->value == 1)
1155 fprintf(output, "MULT div");
1156 else
1157 fprintf(output, "MULT mod");
1158 break;
1159 case XPATH_OP_UNION:
1160 fprintf(output, "UNION"); break;
1161 case XPATH_OP_ROOT:
1162 fprintf(output, "ROOT"); break;
1163 case XPATH_OP_NODE:
1164 fprintf(output, "NODE"); break;
1165 case XPATH_OP_RESET:
1166 fprintf(output, "RESET"); break;
1167 case XPATH_OP_SORT:
1168 fprintf(output, "SORT"); break;
1169 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +00001170 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1171 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1172 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001173 const xmlChar *prefix = op->value4;
1174 const xmlChar *name = op->value5;
1175
1176 fprintf(output, "COLLECT ");
1177 switch (axis) {
1178 case AXIS_ANCESTOR:
1179 fprintf(output, " 'ancestors' "); break;
1180 case AXIS_ANCESTOR_OR_SELF:
1181 fprintf(output, " 'ancestors-or-self' "); break;
1182 case AXIS_ATTRIBUTE:
1183 fprintf(output, " 'attributes' "); break;
1184 case AXIS_CHILD:
1185 fprintf(output, " 'child' "); break;
1186 case AXIS_DESCENDANT:
1187 fprintf(output, " 'descendant' "); break;
1188 case AXIS_DESCENDANT_OR_SELF:
1189 fprintf(output, " 'descendant-or-self' "); break;
1190 case AXIS_FOLLOWING:
1191 fprintf(output, " 'following' "); break;
1192 case AXIS_FOLLOWING_SIBLING:
1193 fprintf(output, " 'following-siblings' "); break;
1194 case AXIS_NAMESPACE:
1195 fprintf(output, " 'namespace' "); break;
1196 case AXIS_PARENT:
1197 fprintf(output, " 'parent' "); break;
1198 case AXIS_PRECEDING:
1199 fprintf(output, " 'preceding' "); break;
1200 case AXIS_PRECEDING_SIBLING:
1201 fprintf(output, " 'preceding-sibling' "); break;
1202 case AXIS_SELF:
1203 fprintf(output, " 'self' "); break;
1204 }
1205 switch (test) {
1206 case NODE_TEST_NONE:
1207 fprintf(output, "'none' "); break;
1208 case NODE_TEST_TYPE:
1209 fprintf(output, "'type' "); break;
1210 case NODE_TEST_PI:
1211 fprintf(output, "'PI' "); break;
1212 case NODE_TEST_ALL:
1213 fprintf(output, "'all' "); break;
1214 case NODE_TEST_NS:
1215 fprintf(output, "'namespace' "); break;
1216 case NODE_TEST_NAME:
1217 fprintf(output, "'name' "); break;
1218 }
1219 switch (type) {
1220 case NODE_TYPE_NODE:
1221 fprintf(output, "'node' "); break;
1222 case NODE_TYPE_COMMENT:
1223 fprintf(output, "'comment' "); break;
1224 case NODE_TYPE_TEXT:
1225 fprintf(output, "'text' "); break;
1226 case NODE_TYPE_PI:
1227 fprintf(output, "'PI' "); break;
1228 }
1229 if (prefix != NULL)
1230 fprintf(output, "%s:", prefix);
1231 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001232 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001233 break;
1234
1235 }
1236 case XPATH_OP_VALUE: {
1237 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1238
1239 fprintf(output, "ELEM ");
1240 xmlXPathDebugDumpObject(output, object, 0);
1241 goto finish;
1242 }
1243 case XPATH_OP_VARIABLE: {
1244 const xmlChar *prefix = op->value5;
1245 const xmlChar *name = op->value4;
1246
1247 if (prefix != NULL)
1248 fprintf(output, "VARIABLE %s:%s", prefix, name);
1249 else
1250 fprintf(output, "VARIABLE %s", name);
1251 break;
1252 }
1253 case XPATH_OP_FUNCTION: {
1254 int nbargs = op->value;
1255 const xmlChar *prefix = op->value5;
1256 const xmlChar *name = op->value4;
1257
1258 if (prefix != NULL)
1259 fprintf(output, "FUNCTION %s:%s(%d args)",
1260 prefix, name, nbargs);
1261 else
1262 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1263 break;
1264 }
1265 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1266 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001267 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001268#ifdef LIBXML_XPTR_ENABLED
1269 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1270#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001271 default:
1272 fprintf(output, "UNKNOWN %d\n", op->op); return;
1273 }
1274 fprintf(output, "\n");
1275finish:
1276 if (op->ch1 >= 0)
1277 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1278 if (op->ch2 >= 0)
1279 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1280}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001281
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001282/**
1283 * xmlXPathDebugDumpCompExpr:
1284 * @output: the FILE * for the output
1285 * @comp: the precompiled XPath expression
1286 * @depth: the indentation level.
1287 *
1288 * Dumps the tree of the compiled XPath expression.
1289 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001290void
1291xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1292 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001293 int i;
1294 char shift[100];
1295
Daniel Veillarda82b1822004-11-08 16:24:57 +00001296 if ((output == NULL) || (comp == NULL)) return;
1297
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001298 for (i = 0;((i < depth) && (i < 25));i++)
1299 shift[2 * i] = shift[2 * i + 1] = ' ';
1300 shift[2 * i] = shift[2 * i + 1] = 0;
1301
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001302 fprintf(output, "%s", shift);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001303
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001304 fprintf(output, "Compiled Expression : %d elements\n",
1305 comp->nbStep);
1306 i = comp->last;
1307 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1308}
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001309
1310#ifdef XP_DEBUG_OBJ_USAGE
1311
1312/*
1313* XPath object usage related debugging variables.
1314*/
1315static int xmlXPathDebugObjCounterUndefined = 0;
1316static int xmlXPathDebugObjCounterNodeset = 0;
1317static int xmlXPathDebugObjCounterBool = 0;
1318static int xmlXPathDebugObjCounterNumber = 0;
1319static int xmlXPathDebugObjCounterString = 0;
1320static int xmlXPathDebugObjCounterPoint = 0;
1321static int xmlXPathDebugObjCounterRange = 0;
1322static int xmlXPathDebugObjCounterLocset = 0;
1323static int xmlXPathDebugObjCounterUsers = 0;
1324static int xmlXPathDebugObjCounterXSLTTree = 0;
1325static int xmlXPathDebugObjCounterAll = 0;
1326
1327static int xmlXPathDebugObjTotalUndefined = 0;
1328static int xmlXPathDebugObjTotalNodeset = 0;
1329static int xmlXPathDebugObjTotalBool = 0;
1330static int xmlXPathDebugObjTotalNumber = 0;
1331static int xmlXPathDebugObjTotalString = 0;
1332static int xmlXPathDebugObjTotalPoint = 0;
1333static int xmlXPathDebugObjTotalRange = 0;
1334static int xmlXPathDebugObjTotalLocset = 0;
1335static int xmlXPathDebugObjTotalUsers = 0;
1336static int xmlXPathDebugObjTotalXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001337static int xmlXPathDebugObjTotalAll = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001338
1339static int xmlXPathDebugObjMaxUndefined = 0;
1340static int xmlXPathDebugObjMaxNodeset = 0;
1341static int xmlXPathDebugObjMaxBool = 0;
1342static int xmlXPathDebugObjMaxNumber = 0;
1343static int xmlXPathDebugObjMaxString = 0;
1344static int xmlXPathDebugObjMaxPoint = 0;
1345static int xmlXPathDebugObjMaxRange = 0;
1346static int xmlXPathDebugObjMaxLocset = 0;
1347static int xmlXPathDebugObjMaxUsers = 0;
1348static int xmlXPathDebugObjMaxXSLTTree = 0;
1349static int xmlXPathDebugObjMaxAll = 0;
1350
1351/* REVISIT TODO: Make this static when committing */
1352static void
1353xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1354{
1355 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001356 if (ctxt->cache != NULL) {
1357 xmlXPathContextCachePtr cache =
1358 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001359
1360 cache->dbgCachedAll = 0;
1361 cache->dbgCachedNodeset = 0;
1362 cache->dbgCachedString = 0;
1363 cache->dbgCachedBool = 0;
1364 cache->dbgCachedNumber = 0;
1365 cache->dbgCachedPoint = 0;
1366 cache->dbgCachedRange = 0;
1367 cache->dbgCachedLocset = 0;
1368 cache->dbgCachedUsers = 0;
1369 cache->dbgCachedXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001370 cache->dbgCachedUndefined = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001371
1372 cache->dbgReusedAll = 0;
1373 cache->dbgReusedNodeset = 0;
1374 cache->dbgReusedString = 0;
1375 cache->dbgReusedBool = 0;
1376 cache->dbgReusedNumber = 0;
1377 cache->dbgReusedPoint = 0;
1378 cache->dbgReusedRange = 0;
1379 cache->dbgReusedLocset = 0;
1380 cache->dbgReusedUsers = 0;
1381 cache->dbgReusedXSLTTree = 0;
1382 cache->dbgReusedUndefined = 0;
1383 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00001384 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001385
1386 xmlXPathDebugObjCounterUndefined = 0;
1387 xmlXPathDebugObjCounterNodeset = 0;
1388 xmlXPathDebugObjCounterBool = 0;
1389 xmlXPathDebugObjCounterNumber = 0;
1390 xmlXPathDebugObjCounterString = 0;
1391 xmlXPathDebugObjCounterPoint = 0;
1392 xmlXPathDebugObjCounterRange = 0;
1393 xmlXPathDebugObjCounterLocset = 0;
1394 xmlXPathDebugObjCounterUsers = 0;
1395 xmlXPathDebugObjCounterXSLTTree = 0;
1396 xmlXPathDebugObjCounterAll = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001397
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001398 xmlXPathDebugObjTotalUndefined = 0;
1399 xmlXPathDebugObjTotalNodeset = 0;
1400 xmlXPathDebugObjTotalBool = 0;
1401 xmlXPathDebugObjTotalNumber = 0;
1402 xmlXPathDebugObjTotalString = 0;
1403 xmlXPathDebugObjTotalPoint = 0;
1404 xmlXPathDebugObjTotalRange = 0;
1405 xmlXPathDebugObjTotalLocset = 0;
1406 xmlXPathDebugObjTotalUsers = 0;
1407 xmlXPathDebugObjTotalXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001408 xmlXPathDebugObjTotalAll = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001409
1410 xmlXPathDebugObjMaxUndefined = 0;
1411 xmlXPathDebugObjMaxNodeset = 0;
1412 xmlXPathDebugObjMaxBool = 0;
1413 xmlXPathDebugObjMaxNumber = 0;
1414 xmlXPathDebugObjMaxString = 0;
1415 xmlXPathDebugObjMaxPoint = 0;
1416 xmlXPathDebugObjMaxRange = 0;
1417 xmlXPathDebugObjMaxLocset = 0;
1418 xmlXPathDebugObjMaxUsers = 0;
1419 xmlXPathDebugObjMaxXSLTTree = 0;
1420 xmlXPathDebugObjMaxAll = 0;
1421
1422}
1423
1424static void
1425xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1426 xmlXPathObjectType objType)
1427{
1428 int isCached = 0;
1429
1430 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001431 if (ctxt->cache != NULL) {
1432 xmlXPathContextCachePtr cache =
1433 (xmlXPathContextCachePtr) ctxt->cache;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001434
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001435 isCached = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001436
1437 cache->dbgReusedAll++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001438 switch (objType) {
1439 case XPATH_UNDEFINED:
1440 cache->dbgReusedUndefined++;
1441 break;
1442 case XPATH_NODESET:
1443 cache->dbgReusedNodeset++;
1444 break;
1445 case XPATH_BOOLEAN:
1446 cache->dbgReusedBool++;
1447 break;
1448 case XPATH_NUMBER:
1449 cache->dbgReusedNumber++;
1450 break;
1451 case XPATH_STRING:
1452 cache->dbgReusedString++;
1453 break;
1454 case XPATH_POINT:
1455 cache->dbgReusedPoint++;
1456 break;
1457 case XPATH_RANGE:
1458 cache->dbgReusedRange++;
1459 break;
1460 case XPATH_LOCATIONSET:
1461 cache->dbgReusedLocset++;
1462 break;
1463 case XPATH_USERS:
1464 cache->dbgReusedUsers++;
1465 break;
1466 case XPATH_XSLT_TREE:
1467 cache->dbgReusedXSLTTree++;
1468 break;
1469 default:
1470 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001471 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001472 }
1473 }
1474
1475 switch (objType) {
1476 case XPATH_UNDEFINED:
1477 if (! isCached)
1478 xmlXPathDebugObjTotalUndefined++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001479 xmlXPathDebugObjCounterUndefined++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001480 if (xmlXPathDebugObjCounterUndefined >
1481 xmlXPathDebugObjMaxUndefined)
1482 xmlXPathDebugObjMaxUndefined =
1483 xmlXPathDebugObjCounterUndefined;
1484 break;
1485 case XPATH_NODESET:
1486 if (! isCached)
1487 xmlXPathDebugObjTotalNodeset++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001488 xmlXPathDebugObjCounterNodeset++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001489 if (xmlXPathDebugObjCounterNodeset >
1490 xmlXPathDebugObjMaxNodeset)
1491 xmlXPathDebugObjMaxNodeset =
1492 xmlXPathDebugObjCounterNodeset;
1493 break;
1494 case XPATH_BOOLEAN:
1495 if (! isCached)
1496 xmlXPathDebugObjTotalBool++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001497 xmlXPathDebugObjCounterBool++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001498 if (xmlXPathDebugObjCounterBool >
1499 xmlXPathDebugObjMaxBool)
1500 xmlXPathDebugObjMaxBool =
1501 xmlXPathDebugObjCounterBool;
1502 break;
1503 case XPATH_NUMBER:
1504 if (! isCached)
1505 xmlXPathDebugObjTotalNumber++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001506 xmlXPathDebugObjCounterNumber++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001507 if (xmlXPathDebugObjCounterNumber >
1508 xmlXPathDebugObjMaxNumber)
1509 xmlXPathDebugObjMaxNumber =
1510 xmlXPathDebugObjCounterNumber;
1511 break;
1512 case XPATH_STRING:
1513 if (! isCached)
1514 xmlXPathDebugObjTotalString++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001515 xmlXPathDebugObjCounterString++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001516 if (xmlXPathDebugObjCounterString >
1517 xmlXPathDebugObjMaxString)
1518 xmlXPathDebugObjMaxString =
1519 xmlXPathDebugObjCounterString;
1520 break;
1521 case XPATH_POINT:
1522 if (! isCached)
1523 xmlXPathDebugObjTotalPoint++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001524 xmlXPathDebugObjCounterPoint++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001525 if (xmlXPathDebugObjCounterPoint >
1526 xmlXPathDebugObjMaxPoint)
1527 xmlXPathDebugObjMaxPoint =
1528 xmlXPathDebugObjCounterPoint;
1529 break;
1530 case XPATH_RANGE:
1531 if (! isCached)
1532 xmlXPathDebugObjTotalRange++;
1533 xmlXPathDebugObjCounterRange++;
1534 if (xmlXPathDebugObjCounterRange >
1535 xmlXPathDebugObjMaxRange)
1536 xmlXPathDebugObjMaxRange =
1537 xmlXPathDebugObjCounterRange;
1538 break;
1539 case XPATH_LOCATIONSET:
1540 if (! isCached)
1541 xmlXPathDebugObjTotalLocset++;
1542 xmlXPathDebugObjCounterLocset++;
1543 if (xmlXPathDebugObjCounterLocset >
1544 xmlXPathDebugObjMaxLocset)
1545 xmlXPathDebugObjMaxLocset =
1546 xmlXPathDebugObjCounterLocset;
1547 break;
1548 case XPATH_USERS:
1549 if (! isCached)
1550 xmlXPathDebugObjTotalUsers++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001551 xmlXPathDebugObjCounterUsers++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001552 if (xmlXPathDebugObjCounterUsers >
1553 xmlXPathDebugObjMaxUsers)
1554 xmlXPathDebugObjMaxUsers =
1555 xmlXPathDebugObjCounterUsers;
1556 break;
1557 case XPATH_XSLT_TREE:
1558 if (! isCached)
1559 xmlXPathDebugObjTotalXSLTTree++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001560 xmlXPathDebugObjCounterXSLTTree++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001561 if (xmlXPathDebugObjCounterXSLTTree >
1562 xmlXPathDebugObjMaxXSLTTree)
1563 xmlXPathDebugObjMaxXSLTTree =
1564 xmlXPathDebugObjCounterXSLTTree;
1565 break;
1566 default:
1567 break;
1568 }
1569 if (! isCached)
1570 xmlXPathDebugObjTotalAll++;
1571 xmlXPathDebugObjCounterAll++;
1572 if (xmlXPathDebugObjCounterAll >
1573 xmlXPathDebugObjMaxAll)
1574 xmlXPathDebugObjMaxAll =
1575 xmlXPathDebugObjCounterAll;
1576}
1577
1578static void
1579xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1580 xmlXPathObjectType objType)
1581{
1582 int isCached = 0;
1583
1584 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001585 if (ctxt->cache != NULL) {
1586 xmlXPathContextCachePtr cache =
1587 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001588
Daniel Veillard45490ae2008-07-29 09:13:19 +00001589 isCached = 1;
1590
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001591 cache->dbgCachedAll++;
1592 switch (objType) {
1593 case XPATH_UNDEFINED:
1594 cache->dbgCachedUndefined++;
1595 break;
1596 case XPATH_NODESET:
1597 cache->dbgCachedNodeset++;
1598 break;
1599 case XPATH_BOOLEAN:
1600 cache->dbgCachedBool++;
1601 break;
1602 case XPATH_NUMBER:
1603 cache->dbgCachedNumber++;
1604 break;
1605 case XPATH_STRING:
1606 cache->dbgCachedString++;
1607 break;
1608 case XPATH_POINT:
1609 cache->dbgCachedPoint++;
1610 break;
1611 case XPATH_RANGE:
1612 cache->dbgCachedRange++;
1613 break;
1614 case XPATH_LOCATIONSET:
1615 cache->dbgCachedLocset++;
1616 break;
1617 case XPATH_USERS:
1618 cache->dbgCachedUsers++;
1619 break;
1620 case XPATH_XSLT_TREE:
1621 cache->dbgCachedXSLTTree++;
1622 break;
1623 default:
1624 break;
1625 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00001626
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001627 }
1628 }
1629 switch (objType) {
1630 case XPATH_UNDEFINED:
1631 xmlXPathDebugObjCounterUndefined--;
1632 break;
1633 case XPATH_NODESET:
1634 xmlXPathDebugObjCounterNodeset--;
1635 break;
1636 case XPATH_BOOLEAN:
1637 xmlXPathDebugObjCounterBool--;
1638 break;
1639 case XPATH_NUMBER:
1640 xmlXPathDebugObjCounterNumber--;
1641 break;
1642 case XPATH_STRING:
1643 xmlXPathDebugObjCounterString--;
1644 break;
1645 case XPATH_POINT:
1646 xmlXPathDebugObjCounterPoint--;
1647 break;
1648 case XPATH_RANGE:
1649 xmlXPathDebugObjCounterRange--;
1650 break;
1651 case XPATH_LOCATIONSET:
1652 xmlXPathDebugObjCounterLocset--;
1653 break;
1654 case XPATH_USERS:
1655 xmlXPathDebugObjCounterUsers--;
1656 break;
1657 case XPATH_XSLT_TREE:
1658 xmlXPathDebugObjCounterXSLTTree--;
1659 break;
1660 default:
1661 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001662 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001663 xmlXPathDebugObjCounterAll--;
1664}
1665
1666/* REVISIT TODO: Make this static when committing */
1667static void
1668xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
1669{
1670 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
1671 reqXSLTTree, reqUndefined;
1672 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
1673 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
1674 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
1675 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
1676 int leftObjs = xmlXPathDebugObjCounterAll;
1677
1678 reqAll = xmlXPathDebugObjTotalAll;
1679 reqNodeset = xmlXPathDebugObjTotalNodeset;
1680 reqString = xmlXPathDebugObjTotalString;
1681 reqBool = xmlXPathDebugObjTotalBool;
1682 reqNumber = xmlXPathDebugObjTotalNumber;
1683 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
1684 reqUndefined = xmlXPathDebugObjTotalUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001685
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001686 printf("# XPath object usage:\n");
1687
1688 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001689 if (ctxt->cache != NULL) {
1690 xmlXPathContextCachePtr cache =
1691 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001692
1693 reAll = cache->dbgReusedAll;
1694 reqAll += reAll;
1695 reNodeset = cache->dbgReusedNodeset;
1696 reqNodeset += reNodeset;
1697 reString = cache->dbgReusedString;
1698 reqString += reString;
1699 reBool = cache->dbgReusedBool;
1700 reqBool += reBool;
1701 reNumber = cache->dbgReusedNumber;
1702 reqNumber += reNumber;
1703 reXSLTTree = cache->dbgReusedXSLTTree;
1704 reqXSLTTree += reXSLTTree;
1705 reUndefined = cache->dbgReusedUndefined;
1706 reqUndefined += reUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001707
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001708 caAll = cache->dbgCachedAll;
1709 caBool = cache->dbgCachedBool;
1710 caNodeset = cache->dbgCachedNodeset;
1711 caString = cache->dbgCachedString;
1712 caNumber = cache->dbgCachedNumber;
1713 caXSLTTree = cache->dbgCachedXSLTTree;
1714 caUndefined = cache->dbgCachedUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001715
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001716 if (cache->nodesetObjs)
1717 leftObjs -= cache->nodesetObjs->number;
1718 if (cache->stringObjs)
1719 leftObjs -= cache->stringObjs->number;
1720 if (cache->booleanObjs)
1721 leftObjs -= cache->booleanObjs->number;
1722 if (cache->numberObjs)
1723 leftObjs -= cache->numberObjs->number;
1724 if (cache->miscObjs)
1725 leftObjs -= cache->miscObjs->number;
1726 }
1727 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00001728
1729 printf("# all\n");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001730 printf("# total : %d\n", reqAll);
1731 printf("# left : %d\n", leftObjs);
1732 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
1733 printf("# reused : %d\n", reAll);
1734 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
1735
1736 printf("# node-sets\n");
1737 printf("# total : %d\n", reqNodeset);
1738 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
1739 printf("# reused : %d\n", reNodeset);
1740 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
1741
1742 printf("# strings\n");
1743 printf("# total : %d\n", reqString);
1744 printf("# created: %d\n", xmlXPathDebugObjTotalString);
1745 printf("# reused : %d\n", reString);
1746 printf("# max : %d\n", xmlXPathDebugObjMaxString);
1747
1748 printf("# booleans\n");
1749 printf("# total : %d\n", reqBool);
1750 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
1751 printf("# reused : %d\n", reBool);
1752 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
1753
1754 printf("# numbers\n");
1755 printf("# total : %d\n", reqNumber);
1756 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
1757 printf("# reused : %d\n", reNumber);
1758 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
1759
1760 printf("# XSLT result tree fragments\n");
1761 printf("# total : %d\n", reqXSLTTree);
1762 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
1763 printf("# reused : %d\n", reXSLTTree);
1764 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
1765
1766 printf("# undefined\n");
1767 printf("# total : %d\n", reqUndefined);
1768 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
1769 printf("# reused : %d\n", reUndefined);
1770 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
1771
1772}
1773
1774#endif /* XP_DEBUG_OBJ_USAGE */
1775
Daniel Veillard017b1082001-06-21 11:20:21 +00001776#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001777
1778/************************************************************************
1779 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001780 * XPath object caching *
1781 * *
1782 ************************************************************************/
1783
1784/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001785 * xmlXPathNewCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001786 *
1787 * Create a new object cache
1788 *
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001789 * Returns the xmlXPathCache just allocated.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001790 */
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001791static xmlXPathContextCachePtr
1792xmlXPathNewCache(void)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001793{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001794 xmlXPathContextCachePtr ret;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001795
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001796 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001797 if (ret == NULL) {
1798 xmlXPathErrMemory(NULL, "creating object cache\n");
1799 return(NULL);
1800 }
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001801 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001802 ret->maxNodeset = 100;
1803 ret->maxString = 100;
1804 ret->maxBoolean = 100;
1805 ret->maxNumber = 100;
1806 ret->maxMisc = 100;
1807 return(ret);
1808}
1809
1810static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001811xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001812{
1813 int i;
1814 xmlXPathObjectPtr obj;
1815
1816 if (list == NULL)
1817 return;
1818
1819 for (i = 0; i < list->number; i++) {
1820 obj = list->items[i];
1821 /*
1822 * Note that it is already assured that we don't need to
1823 * look out for namespace nodes in the node-set.
1824 */
1825 if (obj->nodesetval != NULL) {
1826 if (obj->nodesetval->nodeTab != NULL)
1827 xmlFree(obj->nodesetval->nodeTab);
1828 xmlFree(obj->nodesetval);
1829 }
1830 xmlFree(obj);
1831#ifdef XP_DEBUG_OBJ_USAGE
1832 xmlXPathDebugObjCounterAll--;
1833#endif
1834 }
1835 xmlPointerListFree(list);
1836}
1837
1838static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001839xmlXPathFreeCache(xmlXPathContextCachePtr cache)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001840{
1841 if (cache == NULL)
1842 return;
1843 if (cache->nodesetObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001844 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001845 if (cache->stringObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001846 xmlXPathCacheFreeObjectList(cache->stringObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001847 if (cache->booleanObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001848 xmlXPathCacheFreeObjectList(cache->booleanObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001849 if (cache->numberObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001850 xmlXPathCacheFreeObjectList(cache->numberObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001851 if (cache->miscObjs)
Daniel Veillard45490ae2008-07-29 09:13:19 +00001852 xmlXPathCacheFreeObjectList(cache->miscObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001853 xmlFree(cache);
1854}
1855
1856/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001857 * xmlXPathContextSetCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001858 *
1859 * @ctxt: the XPath context
1860 * @active: enables/disables (creates/frees) the cache
Daniel Veillard45490ae2008-07-29 09:13:19 +00001861 * @value: a value with semantics dependant on @options
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001862 * @options: options (currently only the value 0 is used)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001863 *
1864 * Creates/frees an object cache on the XPath context.
1865 * If activates XPath objects (xmlXPathObject) will be cached internally
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001866 * to be reused.
1867 * @options:
1868 * 0: This will set the XPath object caching:
1869 * @value:
1870 * This will set the maximum number of XPath objects
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001871 * to be cached per slot
1872 * There are 5 slots for: node-set, string, number, boolean, and
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001873 * misc objects. Use <0 for the default number (100).
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001874 * Other values for @options have currently no effect.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001875 *
1876 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1877 */
1878int
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001879xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1880 int active,
1881 int value,
1882 int options)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001883{
1884 if (ctxt == NULL)
1885 return(-1);
1886 if (active) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001887 xmlXPathContextCachePtr cache;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001888
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001889 if (ctxt->cache == NULL) {
1890 ctxt->cache = xmlXPathNewCache();
1891 if (ctxt->cache == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001892 return(-1);
1893 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001894 cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001895 if (options == 0) {
1896 if (value < 0)
1897 value = 100;
1898 cache->maxNodeset = value;
1899 cache->maxString = value;
1900 cache->maxNumber = value;
1901 cache->maxBoolean = value;
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001902 cache->maxMisc = value;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001903 }
1904 } else if (ctxt->cache != NULL) {
1905 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1906 ctxt->cache = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001907 }
1908 return(0);
1909}
1910
1911/**
1912 * xmlXPathCacheWrapNodeSet:
1913 * @ctxt: the XPath context
1914 * @val: the NodePtr value
1915 *
1916 * This is the cached version of xmlXPathWrapNodeSet().
1917 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1918 *
1919 * Returns the created or reused object.
1920 */
1921static xmlXPathObjectPtr
1922xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00001923{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001924 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1925 xmlXPathContextCachePtr cache =
1926 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001927
1928 if ((cache->miscObjs != NULL) &&
1929 (cache->miscObjs->number != 0))
1930 {
1931 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001932
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001933 ret = (xmlXPathObjectPtr)
1934 cache->miscObjs->items[--cache->miscObjs->number];
1935 ret->type = XPATH_NODESET;
1936 ret->nodesetval = val;
1937#ifdef XP_DEBUG_OBJ_USAGE
1938 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
1939#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00001940 return(ret);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001941 }
1942 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00001943
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001944 return(xmlXPathWrapNodeSet(val));
Daniel Veillard45490ae2008-07-29 09:13:19 +00001945
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001946}
1947
1948/**
1949 * xmlXPathCacheWrapString:
1950 * @ctxt: the XPath context
1951 * @val: the xmlChar * value
1952 *
1953 * This is the cached version of xmlXPathWrapString().
1954 * Wraps the @val string into an XPath object.
1955 *
1956 * Returns the created or reused object.
1957 */
1958static xmlXPathObjectPtr
1959xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00001960{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001961 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1962 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001963
1964 if ((cache->stringObjs != NULL) &&
1965 (cache->stringObjs->number != 0))
1966 {
Daniel Veillard45490ae2008-07-29 09:13:19 +00001967
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001968 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001969
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001970 ret = (xmlXPathObjectPtr)
1971 cache->stringObjs->items[--cache->stringObjs->number];
1972 ret->type = XPATH_STRING;
1973 ret->stringval = val;
1974#ifdef XP_DEBUG_OBJ_USAGE
1975 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1976#endif
1977 return(ret);
1978 } else if ((cache->miscObjs != NULL) &&
1979 (cache->miscObjs->number != 0))
1980 {
1981 xmlXPathObjectPtr ret;
1982 /*
1983 * Fallback to misc-cache.
1984 */
1985 ret = (xmlXPathObjectPtr)
1986 cache->miscObjs->items[--cache->miscObjs->number];
1987
1988 ret->type = XPATH_STRING;
1989 ret->stringval = val;
1990#ifdef XP_DEBUG_OBJ_USAGE
1991 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1992#endif
1993 return(ret);
1994 }
1995 }
1996 return(xmlXPathWrapString(val));
1997}
1998
1999/**
2000 * xmlXPathCacheNewNodeSet:
2001 * @ctxt: the XPath context
2002 * @val: the NodePtr value
2003 *
2004 * This is the cached version of xmlXPathNewNodeSet().
2005 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2006 * it with the single Node @val
2007 *
2008 * Returns the created or reused object.
2009 */
2010static xmlXPathObjectPtr
2011xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2012{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002013 if ((ctxt != NULL) && (ctxt->cache)) {
2014 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002015
2016 if ((cache->nodesetObjs != NULL) &&
2017 (cache->nodesetObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002018 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002019 xmlXPathObjectPtr ret;
2020 /*
2021 * Use the nodset-cache.
Daniel Veillard45490ae2008-07-29 09:13:19 +00002022 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002023 ret = (xmlXPathObjectPtr)
2024 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2025 ret->type = XPATH_NODESET;
2026 ret->boolval = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002027 if (val) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002028 if ((ret->nodesetval->nodeMax == 0) ||
2029 (val->type == XML_NAMESPACE_DECL))
2030 {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002031 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002032 } else {
2033 ret->nodesetval->nodeTab[0] = val;
2034 ret->nodesetval->nodeNr = 1;
2035 }
2036 }
2037#ifdef XP_DEBUG_OBJ_USAGE
2038 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2039#endif
2040 return(ret);
2041 } else if ((cache->miscObjs != NULL) &&
2042 (cache->miscObjs->number != 0))
2043 {
2044 xmlXPathObjectPtr ret;
2045 /*
2046 * Fallback to misc-cache.
2047 */
2048
2049 ret = (xmlXPathObjectPtr)
2050 cache->miscObjs->items[--cache->miscObjs->number];
2051
2052 ret->type = XPATH_NODESET;
2053 ret->boolval = 0;
2054 ret->nodesetval = xmlXPathNodeSetCreate(val);
2055#ifdef XP_DEBUG_OBJ_USAGE
2056 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2057#endif
2058 return(ret);
2059 }
2060 }
2061 return(xmlXPathNewNodeSet(val));
2062}
2063
2064/**
2065 * xmlXPathCacheNewCString:
2066 * @ctxt: the XPath context
2067 * @val: the char * value
2068 *
2069 * This is the cached version of xmlXPathNewCString().
2070 * Acquire an xmlXPathObjectPtr of type string and of value @val
2071 *
2072 * Returns the created or reused object.
2073 */
2074static xmlXPathObjectPtr
2075xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002076{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002077 if ((ctxt != NULL) && (ctxt->cache)) {
2078 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002079
2080 if ((cache->stringObjs != NULL) &&
2081 (cache->stringObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002082 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002083 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002084
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002085 ret = (xmlXPathObjectPtr)
2086 cache->stringObjs->items[--cache->stringObjs->number];
2087
2088 ret->type = XPATH_STRING;
2089 ret->stringval = xmlStrdup(BAD_CAST val);
2090#ifdef XP_DEBUG_OBJ_USAGE
2091 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2092#endif
2093 return(ret);
2094 } else if ((cache->miscObjs != NULL) &&
2095 (cache->miscObjs->number != 0))
2096 {
2097 xmlXPathObjectPtr ret;
2098
2099 ret = (xmlXPathObjectPtr)
2100 cache->miscObjs->items[--cache->miscObjs->number];
2101
2102 ret->type = XPATH_STRING;
2103 ret->stringval = xmlStrdup(BAD_CAST val);
2104#ifdef XP_DEBUG_OBJ_USAGE
2105 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2106#endif
2107 return(ret);
2108 }
2109 }
2110 return(xmlXPathNewCString(val));
2111}
2112
2113/**
2114 * xmlXPathCacheNewString:
2115 * @ctxt: the XPath context
2116 * @val: the xmlChar * value
2117 *
2118 * This is the cached version of xmlXPathNewString().
2119 * Acquire an xmlXPathObjectPtr of type string and of value @val
2120 *
2121 * Returns the created or reused object.
2122 */
2123static xmlXPathObjectPtr
2124xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002125{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002126 if ((ctxt != NULL) && (ctxt->cache)) {
2127 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002128
2129 if ((cache->stringObjs != NULL) &&
2130 (cache->stringObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002131 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002132 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002133
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002134 ret = (xmlXPathObjectPtr)
2135 cache->stringObjs->items[--cache->stringObjs->number];
2136 ret->type = XPATH_STRING;
2137 if (val != NULL)
2138 ret->stringval = xmlStrdup(val);
2139 else
2140 ret->stringval = xmlStrdup((const xmlChar *)"");
2141#ifdef XP_DEBUG_OBJ_USAGE
2142 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2143#endif
2144 return(ret);
2145 } else if ((cache->miscObjs != NULL) &&
2146 (cache->miscObjs->number != 0))
2147 {
2148 xmlXPathObjectPtr ret;
2149
2150 ret = (xmlXPathObjectPtr)
2151 cache->miscObjs->items[--cache->miscObjs->number];
2152
2153 ret->type = XPATH_STRING;
2154 if (val != NULL)
2155 ret->stringval = xmlStrdup(val);
2156 else
2157 ret->stringval = xmlStrdup((const xmlChar *)"");
2158#ifdef XP_DEBUG_OBJ_USAGE
2159 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2160#endif
2161 return(ret);
2162 }
2163 }
2164 return(xmlXPathNewString(val));
2165}
2166
2167/**
2168 * xmlXPathCacheNewBoolean:
2169 * @ctxt: the XPath context
2170 * @val: the boolean value
2171 *
2172 * This is the cached version of xmlXPathNewBoolean().
2173 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2174 *
2175 * Returns the created or reused object.
2176 */
2177static xmlXPathObjectPtr
2178xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002179{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002180 if ((ctxt != NULL) && (ctxt->cache)) {
2181 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002182
2183 if ((cache->booleanObjs != NULL) &&
2184 (cache->booleanObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002185 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002186 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002187
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002188 ret = (xmlXPathObjectPtr)
2189 cache->booleanObjs->items[--cache->booleanObjs->number];
2190 ret->type = XPATH_BOOLEAN;
2191 ret->boolval = (val != 0);
2192#ifdef XP_DEBUG_OBJ_USAGE
2193 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2194#endif
2195 return(ret);
2196 } else if ((cache->miscObjs != NULL) &&
2197 (cache->miscObjs->number != 0))
2198 {
2199 xmlXPathObjectPtr ret;
2200
2201 ret = (xmlXPathObjectPtr)
2202 cache->miscObjs->items[--cache->miscObjs->number];
2203
2204 ret->type = XPATH_BOOLEAN;
2205 ret->boolval = (val != 0);
2206#ifdef XP_DEBUG_OBJ_USAGE
2207 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2208#endif
2209 return(ret);
2210 }
2211 }
2212 return(xmlXPathNewBoolean(val));
2213}
2214
2215/**
2216 * xmlXPathCacheNewFloat:
2217 * @ctxt: the XPath context
2218 * @val: the double value
2219 *
2220 * This is the cached version of xmlXPathNewFloat().
2221 * Acquires an xmlXPathObjectPtr of type double and of value @val
2222 *
2223 * Returns the created or reused object.
2224 */
2225static xmlXPathObjectPtr
2226xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2227{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002228 if ((ctxt != NULL) && (ctxt->cache)) {
2229 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002230
2231 if ((cache->numberObjs != NULL) &&
2232 (cache->numberObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002233 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002234 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002235
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002236 ret = (xmlXPathObjectPtr)
2237 cache->numberObjs->items[--cache->numberObjs->number];
2238 ret->type = XPATH_NUMBER;
2239 ret->floatval = val;
2240#ifdef XP_DEBUG_OBJ_USAGE
2241 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2242#endif
2243 return(ret);
2244 } else if ((cache->miscObjs != NULL) &&
2245 (cache->miscObjs->number != 0))
2246 {
2247 xmlXPathObjectPtr ret;
2248
2249 ret = (xmlXPathObjectPtr)
2250 cache->miscObjs->items[--cache->miscObjs->number];
2251
2252 ret->type = XPATH_NUMBER;
2253 ret->floatval = val;
2254#ifdef XP_DEBUG_OBJ_USAGE
2255 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2256#endif
2257 return(ret);
2258 }
2259 }
2260 return(xmlXPathNewFloat(val));
2261}
2262
2263/**
2264 * xmlXPathCacheConvertString:
2265 * @ctxt: the XPath context
2266 * @val: an XPath object
2267 *
2268 * This is the cached version of xmlXPathConvertString().
2269 * Converts an existing object to its string() equivalent
2270 *
2271 * Returns a created or reused object, the old one is freed (cached)
2272 * (or the operation is done directly on @val)
2273 */
2274
2275static xmlXPathObjectPtr
2276xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002277 xmlChar *res = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002278
2279 if (val == NULL)
2280 return(xmlXPathCacheNewCString(ctxt, ""));
2281
2282 switch (val->type) {
2283 case XPATH_UNDEFINED:
2284#ifdef DEBUG_EXPR
2285 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2286#endif
2287 break;
2288 case XPATH_NODESET:
2289 case XPATH_XSLT_TREE:
2290 res = xmlXPathCastNodeSetToString(val->nodesetval);
2291 break;
2292 case XPATH_STRING:
2293 return(val);
2294 case XPATH_BOOLEAN:
2295 res = xmlXPathCastBooleanToString(val->boolval);
2296 break;
2297 case XPATH_NUMBER:
2298 res = xmlXPathCastNumberToString(val->floatval);
2299 break;
2300 case XPATH_USERS:
2301 case XPATH_POINT:
2302 case XPATH_RANGE:
2303 case XPATH_LOCATIONSET:
2304 TODO;
2305 break;
2306 }
2307 xmlXPathReleaseObject(ctxt, val);
2308 if (res == NULL)
2309 return(xmlXPathCacheNewCString(ctxt, ""));
2310 return(xmlXPathCacheWrapString(ctxt, res));
2311}
2312
2313/**
2314 * xmlXPathCacheObjectCopy:
2315 * @ctxt: the XPath context
2316 * @val: the original object
2317 *
2318 * This is the cached version of xmlXPathObjectCopy().
2319 * Acquire a copy of a given object
2320 *
2321 * Returns a created or reused created object.
2322 */
2323static xmlXPathObjectPtr
2324xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2325{
2326 if (val == NULL)
2327 return(NULL);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002328
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002329 if (XP_HAS_CACHE(ctxt)) {
2330 switch (val->type) {
2331 case XPATH_NODESET:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002332 return(xmlXPathCacheWrapNodeSet(ctxt,
2333 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002334 case XPATH_STRING:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002335 return(xmlXPathCacheNewString(ctxt, val->stringval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002336 case XPATH_BOOLEAN:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002337 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002338 case XPATH_NUMBER:
2339 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2340 default:
2341 break;
2342 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002343 }
2344 return(xmlXPathObjectCopy(val));
2345}
2346
2347/**
2348 * xmlXPathCacheConvertBoolean:
2349 * @ctxt: the XPath context
2350 * @val: an XPath object
2351 *
2352 * This is the cached version of xmlXPathConvertBoolean().
2353 * Converts an existing object to its boolean() equivalent
2354 *
2355 * Returns a created or reused object, the old one is freed (or the operation
2356 * is done directly on @val)
2357 */
2358static xmlXPathObjectPtr
2359xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2360 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002361
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002362 if (val == NULL)
2363 return(xmlXPathCacheNewBoolean(ctxt, 0));
2364 if (val->type == XPATH_BOOLEAN)
2365 return(val);
2366 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2367 xmlXPathReleaseObject(ctxt, val);
2368 return(ret);
2369}
2370
2371/**
2372 * xmlXPathCacheConvertNumber:
2373 * @ctxt: the XPath context
2374 * @val: an XPath object
2375 *
2376 * This is the cached version of xmlXPathConvertNumber().
2377 * Converts an existing object to its number() equivalent
2378 *
2379 * Returns a created or reused object, the old one is freed (or the operation
2380 * is done directly on @val)
2381 */
2382static xmlXPathObjectPtr
2383xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2384 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002385
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002386 if (val == NULL)
2387 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2388 if (val->type == XPATH_NUMBER)
2389 return(val);
2390 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2391 xmlXPathReleaseObject(ctxt, val);
2392 return(ret);
2393}
2394
2395/************************************************************************
2396 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +00002397 * Parser stacks related functions and macros *
Owen Taylor3473f882001-02-23 17:55:21 +00002398 * *
2399 ************************************************************************/
2400
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002401/**
Daniel Veillardf5048b32011-08-18 17:10:13 +08002402 * xmlXPathSetFrame:
2403 * @ctxt: an XPath parser context
2404 *
2405 * Set the callee evaluation frame
2406 *
2407 * Returns the previous frame value to be restored once done
2408 */
2409static int
2410xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2411 int ret;
2412
2413 if (ctxt == NULL)
2414 return(0);
2415 ret = ctxt->valueFrame;
2416 ctxt->valueFrame = ctxt->valueNr;
2417 return(ret);
2418}
2419
2420/**
2421 * xmlXPathPopFrame:
2422 * @ctxt: an XPath parser context
2423 * @frame: the previous frame value
2424 *
2425 * Remove the callee evaluation frame
2426 */
2427static void
2428xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2429 if (ctxt == NULL)
2430 return;
2431 if (ctxt->valueNr < ctxt->valueFrame) {
2432 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2433 }
2434 ctxt->valueFrame = frame;
2435}
2436
2437/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002438 * valuePop:
2439 * @ctxt: an XPath evaluation context
2440 *
2441 * Pops the top XPath object from the value stack
2442 *
2443 * Returns the XPath object just removed
2444 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002445xmlXPathObjectPtr
Daniel Veillard1c732d22002-11-30 11:22:59 +00002446valuePop(xmlXPathParserContextPtr ctxt)
2447{
2448 xmlXPathObjectPtr ret;
2449
Daniel Veillarda82b1822004-11-08 16:24:57 +00002450 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
Daniel Veillard24505b02005-07-28 23:49:35 +00002451 return (NULL);
Daniel Veillardf5048b32011-08-18 17:10:13 +08002452
2453 if (ctxt->valueNr <= ctxt->valueFrame) {
2454 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2455 return (NULL);
2456 }
2457
Daniel Veillard1c732d22002-11-30 11:22:59 +00002458 ctxt->valueNr--;
2459 if (ctxt->valueNr > 0)
2460 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2461 else
2462 ctxt->value = NULL;
2463 ret = ctxt->valueTab[ctxt->valueNr];
Daniel Veillard24505b02005-07-28 23:49:35 +00002464 ctxt->valueTab[ctxt->valueNr] = NULL;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002465 return (ret);
2466}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002467/**
2468 * valuePush:
2469 * @ctxt: an XPath evaluation context
2470 * @value: the XPath object
2471 *
2472 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002473 *
2474 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002475 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002476int
Daniel Veillard1c732d22002-11-30 11:22:59 +00002477valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2478{
Daniel Veillarda82b1822004-11-08 16:24:57 +00002479 if ((ctxt == NULL) || (value == NULL)) return(-1);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002480 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002481 xmlXPathObjectPtr *tmp;
2482
2483 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2484 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00002485 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002486 if (tmp == NULL) {
Daniel Veillard1c732d22002-11-30 11:22:59 +00002487 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08002488 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002489 return (0);
2490 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002491 ctxt->valueMax *= 2;
2492 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002493 }
2494 ctxt->valueTab[ctxt->valueNr] = value;
2495 ctxt->value = value;
2496 return (ctxt->valueNr++);
2497}
Owen Taylor3473f882001-02-23 17:55:21 +00002498
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002499/**
2500 * xmlXPathPopBoolean:
2501 * @ctxt: an XPath parser context
2502 *
2503 * Pops a boolean from the stack, handling conversion if needed.
2504 * Check error with #xmlXPathCheckError.
2505 *
2506 * Returns the boolean
2507 */
2508int
2509xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2510 xmlXPathObjectPtr obj;
2511 int ret;
2512
2513 obj = valuePop(ctxt);
2514 if (obj == NULL) {
2515 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2516 return(0);
2517 }
William M. Brack08171912003-12-29 02:52:11 +00002518 if (obj->type != XPATH_BOOLEAN)
2519 ret = xmlXPathCastToBoolean(obj);
2520 else
2521 ret = obj->boolval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002522 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002523 return(ret);
2524}
2525
2526/**
2527 * xmlXPathPopNumber:
2528 * @ctxt: an XPath parser context
2529 *
2530 * Pops a number from the stack, handling conversion if needed.
2531 * Check error with #xmlXPathCheckError.
2532 *
2533 * Returns the number
2534 */
2535double
2536xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2537 xmlXPathObjectPtr obj;
2538 double ret;
2539
2540 obj = valuePop(ctxt);
2541 if (obj == NULL) {
2542 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2543 return(0);
2544 }
William M. Brack08171912003-12-29 02:52:11 +00002545 if (obj->type != XPATH_NUMBER)
2546 ret = xmlXPathCastToNumber(obj);
2547 else
2548 ret = obj->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002549 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002550 return(ret);
2551}
2552
2553/**
2554 * xmlXPathPopString:
2555 * @ctxt: an XPath parser context
2556 *
2557 * Pops a string from the stack, handling conversion if needed.
2558 * Check error with #xmlXPathCheckError.
2559 *
2560 * Returns the string
2561 */
2562xmlChar *
2563xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2564 xmlXPathObjectPtr obj;
2565 xmlChar * ret;
2566
2567 obj = valuePop(ctxt);
2568 if (obj == NULL) {
2569 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2570 return(NULL);
2571 }
William M. Brack08171912003-12-29 02:52:11 +00002572 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002573 /* TODO: needs refactoring somewhere else */
2574 if (obj->stringval == ret)
2575 obj->stringval = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002576 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002577 return(ret);
2578}
2579
2580/**
2581 * xmlXPathPopNodeSet:
2582 * @ctxt: an XPath parser context
2583 *
2584 * Pops a node-set from the stack, handling conversion if needed.
2585 * Check error with #xmlXPathCheckError.
2586 *
2587 * Returns the node-set
2588 */
2589xmlNodeSetPtr
2590xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2591 xmlXPathObjectPtr obj;
2592 xmlNodeSetPtr ret;
2593
Daniel Veillardf2a36f92004-11-08 17:55:01 +00002594 if (ctxt == NULL) return(NULL);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002595 if (ctxt->value == NULL) {
2596 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2597 return(NULL);
2598 }
2599 if (!xmlXPathStackIsNodeSet(ctxt)) {
2600 xmlXPathSetTypeError(ctxt);
2601 return(NULL);
2602 }
2603 obj = valuePop(ctxt);
2604 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00002605#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00002606 /* to fix memory leak of not clearing obj->user */
2607 if (obj->boolval && obj->user != NULL)
2608 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00002609#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002610 obj->nodesetval = NULL;
2611 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002612 return(ret);
2613}
2614
2615/**
2616 * xmlXPathPopExternal:
2617 * @ctxt: an XPath parser context
2618 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002619 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002620 * Check error with #xmlXPathCheckError.
2621 *
2622 * Returns the object
2623 */
2624void *
2625xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2626 xmlXPathObjectPtr obj;
2627 void * ret;
2628
Daniel Veillarda82b1822004-11-08 16:24:57 +00002629 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002630 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2631 return(NULL);
2632 }
2633 if (ctxt->value->type != XPATH_USERS) {
2634 xmlXPathSetTypeError(ctxt);
2635 return(NULL);
2636 }
2637 obj = valuePop(ctxt);
2638 ret = obj->user;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002639 obj->user = NULL;
2640 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002641 return(ret);
2642}
2643
Owen Taylor3473f882001-02-23 17:55:21 +00002644/*
2645 * Macros for accessing the content. Those should be used only by the parser,
2646 * and not exported.
2647 *
2648 * Dirty macros, i.e. one need to make assumption on the context to use them
2649 *
2650 * CUR_PTR return the current pointer to the xmlChar to be parsed.
2651 * CUR returns the current xmlChar value, i.e. a 8 bit value
2652 * in ISO-Latin or UTF-8.
2653 * This should be used internally by the parser
2654 * only to compare to ASCII values otherwise it would break when
2655 * running with UTF-8 encoding.
2656 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
2657 * to compare on ASCII based substring.
2658 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2659 * strings within the parser.
2660 * CURRENT Returns the current char value, with the full decoding of
2661 * UTF-8 if we are using this mode. It returns an int.
2662 * NEXT Skip to the next character, this does the proper decoding
2663 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
2664 * It returns the pointer to the current xmlChar.
2665 */
2666
2667#define CUR (*ctxt->cur)
2668#define SKIP(val) ctxt->cur += (val)
2669#define NXT(val) ctxt->cur[(val)]
2670#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00002671#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2672
2673#define COPY_BUF(l,b,i,v) \
2674 if (l == 1) b[i++] = (xmlChar) v; \
2675 else i += xmlCopyChar(l,&b[i],v)
2676
2677#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00002678
Daniel Veillard45490ae2008-07-29 09:13:19 +00002679#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00002680 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00002681
2682#define CURRENT (*ctxt->cur)
2683#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
2684
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002685
2686#ifndef DBL_DIG
2687#define DBL_DIG 16
2688#endif
2689#ifndef DBL_EPSILON
2690#define DBL_EPSILON 1E-9
2691#endif
2692
2693#define UPPER_DOUBLE 1E9
2694#define LOWER_DOUBLE 1E-5
William M. Brackca797882007-05-11 14:45:53 +00002695#define LOWER_DOUBLE_EXP 5
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002696
2697#define INTEGER_DIGITS DBL_DIG
William M. Brackca797882007-05-11 14:45:53 +00002698#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002699#define EXPONENT_DIGITS (3 + 2)
2700
2701/**
2702 * xmlXPathFormatNumber:
2703 * @number: number to format
2704 * @buffer: output buffer
2705 * @buffersize: size of output buffer
2706 *
2707 * Convert the number into a string representation.
2708 */
2709static void
2710xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2711{
Daniel Veillardcda96922001-08-21 10:56:31 +00002712 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002713 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00002714 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002715 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002716 break;
2717 case -1:
2718 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002719 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002720 break;
2721 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00002722 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002723 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002724 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00002725 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002726 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002727 } else if (number == ((int) number)) {
2728 char work[30];
2729 char *ptr, *cur;
Daniel Veillardb3d14912005-09-04 20:47:39 +00002730 int value = (int) number;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002731
2732 ptr = &buffer[0];
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002733 if (value == 0) {
2734 *ptr++ = '0';
2735 } else {
Daniel Veillardb3d14912005-09-04 20:47:39 +00002736 snprintf(work, 29, "%d", value);
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002737 cur = &work[0];
Daniel Veillardb3d14912005-09-04 20:47:39 +00002738 while ((*cur) && (ptr - buffer < buffersize)) {
2739 *ptr++ = *cur++;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002740 }
2741 }
2742 if (ptr - buffer < buffersize) {
2743 *ptr = 0;
2744 } else if (buffersize > 0) {
2745 ptr--;
2746 *ptr = 0;
2747 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002748 } else {
William M. Brackca797882007-05-11 14:45:53 +00002749 /*
2750 For the dimension of work,
2751 DBL_DIG is number of significant digits
2752 EXPONENT is only needed for "scientific notation"
2753 3 is sign, decimal point, and terminating zero
2754 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2755 Note that this dimension is slightly (a few characters)
2756 larger than actually necessary.
2757 */
2758 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
Bjorn Reese70a9da52001-04-21 16:57:29 +00002759 int integer_place, fraction_place;
2760 char *ptr;
2761 char *after_fraction;
2762 double absolute_value;
2763 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002764
Bjorn Reese70a9da52001-04-21 16:57:29 +00002765 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002766
Bjorn Reese70a9da52001-04-21 16:57:29 +00002767 /*
2768 * First choose format - scientific or regular floating point.
2769 * In either case, result is in work, and after_fraction points
2770 * just past the fractional part.
2771 */
2772 if ( ((absolute_value > UPPER_DOUBLE) ||
2773 (absolute_value < LOWER_DOUBLE)) &&
2774 (absolute_value != 0.0) ) {
2775 /* Use scientific notation */
2776 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2777 fraction_place = DBL_DIG - 1;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002778 size = snprintf(work, sizeof(work),"%*.*e",
Bjorn Reese70a9da52001-04-21 16:57:29 +00002779 integer_place, fraction_place, number);
Daniel Veillard11ce4002006-03-10 00:36:23 +00002780 while ((size > 0) && (work[size] != 'e')) size--;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002781
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002782 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002783 else {
2784 /* Use regular notation */
William M. Brackca797882007-05-11 14:45:53 +00002785 if (absolute_value > 0.0) {
2786 integer_place = (int)log10(absolute_value);
2787 if (integer_place > 0)
2788 fraction_place = DBL_DIG - integer_place - 1;
2789 else
2790 fraction_place = DBL_DIG - integer_place;
2791 } else {
2792 fraction_place = 1;
2793 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002794 size = snprintf(work, sizeof(work), "%0.*f",
2795 fraction_place, number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002796 }
2797
Bjorn Reese70a9da52001-04-21 16:57:29 +00002798 /* Remove fractional trailing zeroes */
William M. Brackca797882007-05-11 14:45:53 +00002799 after_fraction = work + size;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002800 ptr = after_fraction;
2801 while (*(--ptr) == '0')
2802 ;
2803 if (*ptr != '.')
2804 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002805 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002806
2807 /* Finally copy result back to caller */
2808 size = strlen(work) + 1;
2809 if (size > buffersize) {
2810 work[buffersize - 1] = 0;
2811 size = buffersize;
2812 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002813 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002814 }
2815 break;
2816 }
2817}
2818
Owen Taylor3473f882001-02-23 17:55:21 +00002819
2820/************************************************************************
2821 * *
2822 * Routines to handle NodeSets *
2823 * *
2824 ************************************************************************/
2825
2826/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002827 * xmlXPathOrderDocElems:
2828 * @doc: an input document
2829 *
2830 * Call this routine to speed up XPath computation on static documents.
2831 * This stamps all the element nodes with the document order
2832 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00002833 * field, the value stored is actually - the node number (starting at -1)
2834 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002835 *
William M. Brack08171912003-12-29 02:52:11 +00002836 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002837 * of error.
2838 */
2839long
2840xmlXPathOrderDocElems(xmlDocPtr doc) {
2841 long count = 0;
2842 xmlNodePtr cur;
2843
2844 if (doc == NULL)
2845 return(-1);
2846 cur = doc->children;
2847 while (cur != NULL) {
2848 if (cur->type == XML_ELEMENT_NODE) {
2849 cur->content = (void *) (-(++count));
2850 if (cur->children != NULL) {
2851 cur = cur->children;
2852 continue;
2853 }
2854 }
2855 if (cur->next != NULL) {
2856 cur = cur->next;
2857 continue;
2858 }
2859 do {
2860 cur = cur->parent;
2861 if (cur == NULL)
2862 break;
2863 if (cur == (xmlNodePtr) doc) {
2864 cur = NULL;
2865 break;
2866 }
2867 if (cur->next != NULL) {
2868 cur = cur->next;
2869 break;
2870 }
2871 } while (cur != NULL);
2872 }
2873 return(count);
2874}
2875
2876/**
Owen Taylor3473f882001-02-23 17:55:21 +00002877 * xmlXPathCmpNodes:
2878 * @node1: the first node
2879 * @node2: the second node
2880 *
2881 * Compare two nodes w.r.t document order
2882 *
2883 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00002884 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00002885 */
2886int
2887xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2888 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002889 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002890 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002891 xmlNodePtr cur, root;
2892
2893 if ((node1 == NULL) || (node2 == NULL))
2894 return(-2);
2895 /*
2896 * a couple of optimizations which will avoid computations in most cases
2897 */
William M. Brackee0b9822007-03-07 08:15:01 +00002898 if (node1 == node2) /* trivial case */
2899 return(0);
Daniel Veillardedfd5882003-03-07 14:20:40 +00002900 if (node1->type == XML_ATTRIBUTE_NODE) {
2901 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002902 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002903 node1 = node1->parent;
2904 }
2905 if (node2->type == XML_ATTRIBUTE_NODE) {
2906 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002907 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002908 node2 = node2->parent;
2909 }
2910 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00002911 if (attr1 == attr2) {
2912 /* not required, but we keep attributes in order */
2913 if (attr1 != 0) {
2914 cur = attrNode2->prev;
2915 while (cur != NULL) {
2916 if (cur == attrNode1)
2917 return (1);
2918 cur = cur->prev;
2919 }
2920 return (-1);
2921 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00002922 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00002923 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00002924 if (attr2 == 1)
2925 return(1);
2926 return(-1);
2927 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002928 if ((node1->type == XML_NAMESPACE_DECL) ||
2929 (node2->type == XML_NAMESPACE_DECL))
2930 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00002931 if (node1 == node2->prev)
2932 return(1);
2933 if (node1 == node2->next)
2934 return(-1);
2935
2936 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002937 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002938 */
2939 if ((node1->type == XML_ELEMENT_NODE) &&
2940 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002941 (0 > (long) node1->content) &&
2942 (0 > (long) node2->content) &&
2943 (node1->doc == node2->doc)) {
2944 long l1, l2;
2945
2946 l1 = -((long) node1->content);
2947 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002948 if (l1 < l2)
2949 return(1);
2950 if (l1 > l2)
2951 return(-1);
2952 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002953
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002954 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002955 * compute depth to root
2956 */
2957 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2958 if (cur == node1)
2959 return(1);
2960 depth2++;
2961 }
2962 root = cur;
2963 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2964 if (cur == node2)
2965 return(-1);
2966 depth1++;
2967 }
2968 /*
2969 * Distinct document (or distinct entities :-( ) case.
2970 */
2971 if (root != cur) {
2972 return(-2);
2973 }
2974 /*
2975 * get the nearest common ancestor.
2976 */
2977 while (depth1 > depth2) {
2978 depth1--;
2979 node1 = node1->parent;
2980 }
2981 while (depth2 > depth1) {
2982 depth2--;
2983 node2 = node2->parent;
2984 }
2985 while (node1->parent != node2->parent) {
2986 node1 = node1->parent;
2987 node2 = node2->parent;
2988 /* should not happen but just in case ... */
2989 if ((node1 == NULL) || (node2 == NULL))
2990 return(-2);
2991 }
2992 /*
2993 * Find who's first.
2994 */
Daniel Veillardf49be472004-02-17 11:48:18 +00002995 if (node1 == node2->prev)
2996 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00002997 if (node1 == node2->next)
2998 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00002999 /*
3000 * Speedup using document order if availble.
3001 */
3002 if ((node1->type == XML_ELEMENT_NODE) &&
3003 (node2->type == XML_ELEMENT_NODE) &&
3004 (0 > (long) node1->content) &&
3005 (0 > (long) node2->content) &&
3006 (node1->doc == node2->doc)) {
3007 long l1, l2;
3008
3009 l1 = -((long) node1->content);
3010 l2 = -((long) node2->content);
3011 if (l1 < l2)
3012 return(1);
3013 if (l1 > l2)
3014 return(-1);
3015 }
3016
Owen Taylor3473f882001-02-23 17:55:21 +00003017 for (cur = node1->next;cur != NULL;cur = cur->next)
3018 if (cur == node2)
3019 return(1);
3020 return(-1); /* assume there is no sibling list corruption */
3021}
3022
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003023#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003024/**
3025 * xmlXPathCmpNodesExt:
3026 * @node1: the first node
3027 * @node2: the second node
3028 *
3029 * Compare two nodes w.r.t document order.
3030 * This one is optimized for handling of non-element nodes.
3031 *
3032 * Returns -2 in case of error 1 if first point < second point, 0 if
3033 * it's the same node, -1 otherwise
3034 */
3035static int
3036xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
3037 int depth1, depth2;
3038 int misc = 0, precedence1 = 0, precedence2 = 0;
3039 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
3040 xmlNodePtr cur, root;
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003041 long l1, l2;
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003042
3043 if ((node1 == NULL) || (node2 == NULL))
3044 return(-2);
3045
3046 if (node1 == node2)
3047 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00003048
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003049 /*
3050 * a couple of optimizations which will avoid computations in most cases
Daniel Veillard45490ae2008-07-29 09:13:19 +00003051 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003052 switch (node1->type) {
3053 case XML_ELEMENT_NODE:
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003054 if (node2->type == XML_ELEMENT_NODE) {
3055 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
3056 (0 > (long) node2->content) &&
3057 (node1->doc == node2->doc))
Daniel Veillard45490ae2008-07-29 09:13:19 +00003058 {
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003059 l1 = -((long) node1->content);
3060 l2 = -((long) node2->content);
3061 if (l1 < l2)
3062 return(1);
3063 if (l1 > l2)
3064 return(-1);
3065 } else
Daniel Veillard45490ae2008-07-29 09:13:19 +00003066 goto turtle_comparison;
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003067 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003068 break;
3069 case XML_ATTRIBUTE_NODE:
3070 precedence1 = 1; /* element is owner */
3071 miscNode1 = node1;
3072 node1 = node1->parent;
3073 misc = 1;
3074 break;
3075 case XML_TEXT_NODE:
3076 case XML_CDATA_SECTION_NODE:
3077 case XML_COMMENT_NODE:
3078 case XML_PI_NODE: {
3079 miscNode1 = node1;
3080 /*
3081 * Find nearest element node.
Daniel Veillard45490ae2008-07-29 09:13:19 +00003082 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003083 if (node1->prev != NULL) {
3084 do {
3085 node1 = node1->prev;
3086 if (node1->type == XML_ELEMENT_NODE) {
3087 precedence1 = 3; /* element in prev-sibl axis */
3088 break;
3089 }
3090 if (node1->prev == NULL) {
3091 precedence1 = 2; /* element is parent */
3092 /*
3093 * URGENT TODO: Are there any cases, where the
3094 * parent of such a node is not an element node?
3095 */
3096 node1 = node1->parent;
3097 break;
3098 }
3099 } while (1);
3100 } else {
3101 precedence1 = 2; /* element is parent */
3102 node1 = node1->parent;
3103 }
William M. Brack31700e62007-06-13 20:33:02 +00003104 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
3105 (0 <= (long) node1->content)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003106 /*
3107 * Fallback for whatever case.
3108 */
3109 node1 = miscNode1;
3110 precedence1 = 0;
3111 } else
3112 misc = 1;
3113 }
3114 break;
3115 case XML_NAMESPACE_DECL:
3116 /*
3117 * TODO: why do we return 1 for namespace nodes?
3118 */
3119 return(1);
3120 default:
3121 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00003122 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003123 switch (node2->type) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00003124 case XML_ELEMENT_NODE:
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003125 break;
3126 case XML_ATTRIBUTE_NODE:
3127 precedence2 = 1; /* element is owner */
3128 miscNode2 = node2;
3129 node2 = node2->parent;
3130 misc = 1;
3131 break;
3132 case XML_TEXT_NODE:
3133 case XML_CDATA_SECTION_NODE:
3134 case XML_COMMENT_NODE:
3135 case XML_PI_NODE: {
3136 miscNode2 = node2;
3137 if (node2->prev != NULL) {
3138 do {
3139 node2 = node2->prev;
3140 if (node2->type == XML_ELEMENT_NODE) {
3141 precedence2 = 3; /* element in prev-sibl axis */
3142 break;
3143 }
3144 if (node2->prev == NULL) {
3145 precedence2 = 2; /* element is parent */
3146 node2 = node2->parent;
3147 break;
3148 }
3149 } while (1);
3150 } else {
3151 precedence2 = 2; /* element is parent */
3152 node2 = node2->parent;
Daniel Veillard45490ae2008-07-29 09:13:19 +00003153 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003154 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3155 (0 <= (long) node1->content))
3156 {
3157 node2 = miscNode2;
3158 precedence2 = 0;
3159 } else
3160 misc = 1;
3161 }
3162 break;
3163 case XML_NAMESPACE_DECL:
3164 return(1);
3165 default:
3166 break;
3167 }
3168 if (misc) {
3169 if (node1 == node2) {
3170 if (precedence1 == precedence2) {
3171 /*
3172 * The ugly case; but normally there aren't many
3173 * adjacent non-element nodes around.
3174 */
3175 cur = miscNode2->prev;
3176 while (cur != NULL) {
3177 if (cur == miscNode1)
3178 return(1);
3179 if (cur->type == XML_ELEMENT_NODE)
3180 return(-1);
3181 cur = cur->prev;
3182 }
3183 return (-1);
3184 } else {
3185 /*
3186 * Evaluate based on higher precedence wrt to the element.
3187 * TODO: This assumes attributes are sorted before content.
3188 * Is this 100% correct?
3189 */
3190 if (precedence1 < precedence2)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003191 return(1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003192 else
Daniel Veillard45490ae2008-07-29 09:13:19 +00003193 return(-1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003194 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00003195 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003196 /*
3197 * Special case: One of the helper-elements is contained by the other.
3198 * <foo>
3199 * <node2>
3200 * <node1>Text-1(precedence1 == 2)</node1>
3201 * </node2>
3202 * Text-6(precedence2 == 3)
3203 * </foo>
Daniel Veillard45490ae2008-07-29 09:13:19 +00003204 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003205 if ((precedence2 == 3) && (precedence1 > 1)) {
3206 cur = node1->parent;
3207 while (cur) {
3208 if (cur == node2)
3209 return(1);
3210 cur = cur->parent;
3211 }
3212 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00003213 if ((precedence1 == 3) && (precedence2 > 1)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003214 cur = node2->parent;
3215 while (cur) {
3216 if (cur == node1)
3217 return(-1);
3218 cur = cur->parent;
3219 }
3220 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00003221 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003222
3223 /*
3224 * Speedup using document order if availble.
3225 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00003226 if ((node1->type == XML_ELEMENT_NODE) &&
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003227 (node2->type == XML_ELEMENT_NODE) &&
3228 (0 > (long) node1->content) &&
3229 (0 > (long) node2->content) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +00003230 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003231
3232 l1 = -((long) node1->content);
3233 l2 = -((long) node2->content);
3234 if (l1 < l2)
3235 return(1);
3236 if (l1 > l2)
3237 return(-1);
3238 }
3239
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003240turtle_comparison:
3241
3242 if (node1 == node2->prev)
3243 return(1);
3244 if (node1 == node2->next)
3245 return(-1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003246 /*
3247 * compute depth to root
3248 */
3249 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3250 if (cur == node1)
3251 return(1);
3252 depth2++;
3253 }
3254 root = cur;
3255 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3256 if (cur == node2)
3257 return(-1);
3258 depth1++;
3259 }
3260 /*
3261 * Distinct document (or distinct entities :-( ) case.
3262 */
3263 if (root != cur) {
3264 return(-2);
3265 }
3266 /*
3267 * get the nearest common ancestor.
3268 */
3269 while (depth1 > depth2) {
3270 depth1--;
3271 node1 = node1->parent;
3272 }
3273 while (depth2 > depth1) {
3274 depth2--;
3275 node2 = node2->parent;
3276 }
3277 while (node1->parent != node2->parent) {
3278 node1 = node1->parent;
3279 node2 = node2->parent;
3280 /* should not happen but just in case ... */
3281 if ((node1 == NULL) || (node2 == NULL))
3282 return(-2);
3283 }
3284 /*
3285 * Find who's first.
3286 */
3287 if (node1 == node2->prev)
3288 return(1);
3289 if (node1 == node2->next)
3290 return(-1);
3291 /*
3292 * Speedup using document order if availble.
3293 */
3294 if ((node1->type == XML_ELEMENT_NODE) &&
3295 (node2->type == XML_ELEMENT_NODE) &&
3296 (0 > (long) node1->content) &&
3297 (0 > (long) node2->content) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +00003298 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003299
3300 l1 = -((long) node1->content);
3301 l2 = -((long) node2->content);
3302 if (l1 < l2)
3303 return(1);
3304 if (l1 > l2)
3305 return(-1);
3306 }
3307
3308 for (cur = node1->next;cur != NULL;cur = cur->next)
3309 if (cur == node2)
3310 return(1);
3311 return(-1); /* assume there is no sibling list corruption */
3312}
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003313#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003314
Owen Taylor3473f882001-02-23 17:55:21 +00003315/**
3316 * xmlXPathNodeSetSort:
3317 * @set: the node set
3318 *
3319 * Sort the node set in document order
3320 */
3321void
3322xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003323 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003324 xmlNodePtr tmp;
3325
3326 if (set == NULL)
3327 return;
3328
3329 /* Use Shell's sort to sort the node-set */
3330 len = set->nodeNr;
3331 for (incr = len / 2; incr > 0; incr /= 2) {
3332 for (i = incr; i < len; i++) {
3333 j = i - incr;
3334 while (j >= 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003335#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003336 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3337 set->nodeTab[j + incr]) == -1)
3338#else
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003339 if (xmlXPathCmpNodes(set->nodeTab[j],
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003340 set->nodeTab[j + incr]) == -1)
3341#endif
3342 {
Owen Taylor3473f882001-02-23 17:55:21 +00003343 tmp = set->nodeTab[j];
3344 set->nodeTab[j] = set->nodeTab[j + incr];
3345 set->nodeTab[j + incr] = tmp;
3346 j -= incr;
3347 } else
3348 break;
3349 }
3350 }
3351 }
3352}
3353
3354#define XML_NODESET_DEFAULT 10
3355/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003356 * xmlXPathNodeSetDupNs:
3357 * @node: the parent node of the namespace XPath node
3358 * @ns: the libxml namespace declaration node.
3359 *
3360 * Namespace node in libxml don't match the XPath semantic. In a node set
3361 * the namespace nodes are duplicated and the next pointer is set to the
3362 * parent node in the XPath semantic.
3363 *
3364 * Returns the newly created object.
3365 */
3366static xmlNodePtr
3367xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3368 xmlNsPtr cur;
3369
3370 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3371 return(NULL);
3372 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3373 return((xmlNodePtr) ns);
3374
3375 /*
3376 * Allocate a new Namespace and fill the fields.
3377 */
3378 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3379 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003380 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003381 return(NULL);
3382 }
3383 memset(cur, 0, sizeof(xmlNs));
3384 cur->type = XML_NAMESPACE_DECL;
3385 if (ns->href != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003386 cur->href = xmlStrdup(ns->href);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003387 if (ns->prefix != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003388 cur->prefix = xmlStrdup(ns->prefix);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003389 cur->next = (xmlNsPtr) node;
3390 return((xmlNodePtr) cur);
3391}
3392
3393/**
3394 * xmlXPathNodeSetFreeNs:
3395 * @ns: the XPath namespace node found in a nodeset.
3396 *
William M. Brack08171912003-12-29 02:52:11 +00003397 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003398 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00003399 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003400 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00003401void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003402xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3403 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3404 return;
3405
3406 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3407 if (ns->href != NULL)
3408 xmlFree((xmlChar *)ns->href);
3409 if (ns->prefix != NULL)
3410 xmlFree((xmlChar *)ns->prefix);
3411 xmlFree(ns);
3412 }
3413}
3414
3415/**
Owen Taylor3473f882001-02-23 17:55:21 +00003416 * xmlXPathNodeSetCreate:
3417 * @val: an initial xmlNodePtr, or NULL
3418 *
3419 * Create a new xmlNodeSetPtr of type double and of value @val
3420 *
3421 * Returns the newly created object.
3422 */
3423xmlNodeSetPtr
3424xmlXPathNodeSetCreate(xmlNodePtr val) {
3425 xmlNodeSetPtr ret;
3426
3427 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3428 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003429 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003430 return(NULL);
3431 }
3432 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3433 if (val != NULL) {
3434 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3435 sizeof(xmlNodePtr));
3436 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003437 xmlXPathErrMemory(NULL, "creating nodeset\n");
3438 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003439 return(NULL);
3440 }
3441 memset(ret->nodeTab, 0 ,
3442 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3443 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003444 if (val->type == XML_NAMESPACE_DECL) {
3445 xmlNsPtr ns = (xmlNsPtr) val;
3446
3447 ret->nodeTab[ret->nodeNr++] =
3448 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3449 } else
3450 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003451 }
3452 return(ret);
3453}
3454
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003455/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003456 * xmlXPathNodeSetCreateSize:
3457 * @size: the initial size of the set
3458 *
3459 * Create a new xmlNodeSetPtr of type double and of value @val
3460 *
3461 * Returns the newly created object.
3462 */
3463static xmlNodeSetPtr
3464xmlXPathNodeSetCreateSize(int size) {
3465 xmlNodeSetPtr ret;
3466
3467 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3468 if (ret == NULL) {
3469 xmlXPathErrMemory(NULL, "creating nodeset\n");
3470 return(NULL);
3471 }
3472 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3473 if (size < XML_NODESET_DEFAULT)
3474 size = XML_NODESET_DEFAULT;
3475 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3476 if (ret->nodeTab == NULL) {
3477 xmlXPathErrMemory(NULL, "creating nodeset\n");
3478 xmlFree(ret);
3479 return(NULL);
3480 }
3481 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
Daniel Veillard45490ae2008-07-29 09:13:19 +00003482 ret->nodeMax = size;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003483 return(ret);
3484}
3485
3486/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003487 * xmlXPathNodeSetContains:
3488 * @cur: the node-set
3489 * @val: the node
3490 *
3491 * checks whether @cur contains @val
3492 *
3493 * Returns true (1) if @cur contains @val, false (0) otherwise
3494 */
3495int
3496xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3497 int i;
3498
Daniel Veillarda82b1822004-11-08 16:24:57 +00003499 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003500 if (val->type == XML_NAMESPACE_DECL) {
3501 for (i = 0; i < cur->nodeNr; i++) {
3502 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3503 xmlNsPtr ns1, ns2;
3504
3505 ns1 = (xmlNsPtr) val;
3506 ns2 = (xmlNsPtr) cur->nodeTab[i];
3507 if (ns1 == ns2)
3508 return(1);
3509 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3510 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3511 return(1);
3512 }
3513 }
3514 } else {
3515 for (i = 0; i < cur->nodeNr; i++) {
3516 if (cur->nodeTab[i] == val)
3517 return(1);
3518 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003519 }
3520 return(0);
3521}
3522
3523/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003524 * xmlXPathNodeSetAddNs:
3525 * @cur: the initial node set
3526 * @node: the hosting node
3527 * @ns: a the namespace node
3528 *
3529 * add a new namespace node to an existing NodeSet
3530 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00003531void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003532xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3533 int i;
3534
Daniel Veillard45490ae2008-07-29 09:13:19 +00003535
Daniel Veillarda82b1822004-11-08 16:24:57 +00003536 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3537 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003538 (node->type != XML_ELEMENT_NODE))
3539 return;
3540
William M. Brack08171912003-12-29 02:52:11 +00003541 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003542 /*
William M. Brack08171912003-12-29 02:52:11 +00003543 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003544 */
3545 for (i = 0;i < cur->nodeNr;i++) {
3546 if ((cur->nodeTab[i] != NULL) &&
3547 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00003548 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003549 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3550 return;
3551 }
3552
3553 /*
3554 * grow the nodeTab if needed
3555 */
3556 if (cur->nodeMax == 0) {
3557 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3558 sizeof(xmlNodePtr));
3559 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003560 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003561 return;
3562 }
3563 memset(cur->nodeTab, 0 ,
3564 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3565 cur->nodeMax = XML_NODESET_DEFAULT;
3566 } else if (cur->nodeNr == cur->nodeMax) {
3567 xmlNodePtr *temp;
3568
Chris Evansd7958b22011-03-23 08:13:06 +08003569 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003570 sizeof(xmlNodePtr));
3571 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003572 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003573 return;
3574 }
Chris Evansd7958b22011-03-23 08:13:06 +08003575 cur->nodeMax *= 2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003576 cur->nodeTab = temp;
3577 }
3578 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3579}
3580
3581/**
Owen Taylor3473f882001-02-23 17:55:21 +00003582 * xmlXPathNodeSetAdd:
3583 * @cur: the initial node set
3584 * @val: a new xmlNodePtr
3585 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003586 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00003587 */
3588void
3589xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3590 int i;
3591
Daniel Veillarda82b1822004-11-08 16:24:57 +00003592 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003593
Daniel Veillardef0b4502003-03-24 13:57:34 +00003594#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00003595 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3596 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00003597#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00003598
William M. Brack08171912003-12-29 02:52:11 +00003599 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003600 /*
William M. Brack08171912003-12-29 02:52:11 +00003601 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00003602 */
3603 for (i = 0;i < cur->nodeNr;i++)
3604 if (cur->nodeTab[i] == val) return;
3605
3606 /*
3607 * grow the nodeTab if needed
3608 */
3609 if (cur->nodeMax == 0) {
3610 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3611 sizeof(xmlNodePtr));
3612 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003613 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003614 return;
3615 }
3616 memset(cur->nodeTab, 0 ,
3617 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3618 cur->nodeMax = XML_NODESET_DEFAULT;
3619 } else if (cur->nodeNr == cur->nodeMax) {
3620 xmlNodePtr *temp;
3621
Daniel Veillard0cbeb502010-11-15 12:06:29 +01003622 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003623 sizeof(xmlNodePtr));
3624 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003625 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003626 return;
3627 }
Daniel Veillard0cbeb502010-11-15 12:06:29 +01003628 cur->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003629 cur->nodeTab = temp;
3630 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003631 if (val->type == XML_NAMESPACE_DECL) {
3632 xmlNsPtr ns = (xmlNsPtr) val;
3633
Daniel Veillard45490ae2008-07-29 09:13:19 +00003634 cur->nodeTab[cur->nodeNr++] =
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003635 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3636 } else
3637 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003638}
3639
3640/**
3641 * xmlXPathNodeSetAddUnique:
3642 * @cur: the initial node set
3643 * @val: a new xmlNodePtr
3644 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003645 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00003646 * when we are sure the node is not already in the set.
3647 */
3648void
3649xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00003650 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003651
Daniel Veillardef0b4502003-03-24 13:57:34 +00003652#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00003653 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3654 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00003655#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00003656
William M. Brack08171912003-12-29 02:52:11 +00003657 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003658 /*
3659 * grow the nodeTab if needed
3660 */
3661 if (cur->nodeMax == 0) {
3662 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3663 sizeof(xmlNodePtr));
3664 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003665 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003666 return;
3667 }
3668 memset(cur->nodeTab, 0 ,
3669 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3670 cur->nodeMax = XML_NODESET_DEFAULT;
3671 } else if (cur->nodeNr == cur->nodeMax) {
3672 xmlNodePtr *temp;
3673
Chris Evansd7958b22011-03-23 08:13:06 +08003674 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003675 sizeof(xmlNodePtr));
3676 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003677 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003678 return;
3679 }
3680 cur->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08003681 cur->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003682 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003683 if (val->type == XML_NAMESPACE_DECL) {
3684 xmlNsPtr ns = (xmlNsPtr) val;
3685
Daniel Veillard45490ae2008-07-29 09:13:19 +00003686 cur->nodeTab[cur->nodeNr++] =
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003687 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3688 } else
3689 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003690}
3691
3692/**
3693 * xmlXPathNodeSetMerge:
3694 * @val1: the first NodeSet or NULL
3695 * @val2: the second NodeSet
3696 *
3697 * Merges two nodesets, all nodes from @val2 are added to @val1
3698 * if @val1 is NULL, a new set is created and copied from @val2
3699 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003700 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003701 */
3702xmlNodeSetPtr
3703xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003704 int i, j, initNr, skip;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003705 xmlNodePtr n1, n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003706
3707 if (val2 == NULL) return(val1);
3708 if (val1 == NULL) {
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003709 val1 = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00003710 if (val1 == NULL)
3711 return (NULL);
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003712#if 0
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003713 /*
3714 * TODO: The optimization won't work in every case, since
3715 * those nasty namespace nodes need to be added with
3716 * xmlXPathNodeSetDupNs() to the set; thus a pure
3717 * memcpy is not possible.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00003718 * If there was a flag on the nodesetval, indicating that
3719 * some temporary nodes are in, that would be helpfull.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003720 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00003721 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003722 * Optimization: Create an equally sized node-set
3723 * and memcpy the content.
3724 */
3725 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3726 if (val1 == NULL)
3727 return(NULL);
3728 if (val2->nodeNr != 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003729 if (val2->nodeNr == 1)
3730 *(val1->nodeTab) = *(val2->nodeTab);
3731 else {
3732 memcpy(val1->nodeTab, val2->nodeTab,
3733 val2->nodeNr * sizeof(xmlNodePtr));
3734 }
3735 val1->nodeNr = val2->nodeNr;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003736 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003737 return(val1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003738#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003739 }
3740
William M. Brack08171912003-12-29 02:52:11 +00003741 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003742 initNr = val1->nodeNr;
3743
3744 for (i = 0;i < val2->nodeNr;i++) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00003745 n2 = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00003746 /*
William M. Brack08171912003-12-29 02:52:11 +00003747 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003748 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003749 skip = 0;
3750 for (j = 0; j < initNr; j++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003751 n1 = val1->nodeTab[j];
3752 if (n1 == n2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003753 skip = 1;
3754 break;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003755 } else if ((n1->type == XML_NAMESPACE_DECL) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +00003756 (n2->type == XML_NAMESPACE_DECL)) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003757 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3758 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3759 ((xmlNsPtr) n2)->prefix)))
3760 {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003761 skip = 1;
3762 break;
3763 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003764 }
3765 }
3766 if (skip)
3767 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00003768
3769 /*
3770 * grow the nodeTab if needed
3771 */
3772 if (val1->nodeMax == 0) {
3773 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3774 sizeof(xmlNodePtr));
3775 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003776 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003777 return(NULL);
3778 }
3779 memset(val1->nodeTab, 0 ,
3780 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3781 val1->nodeMax = XML_NODESET_DEFAULT;
3782 } else if (val1->nodeNr == val1->nodeMax) {
3783 xmlNodePtr *temp;
3784
Chris Evansd7958b22011-03-23 08:13:06 +08003785 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003786 sizeof(xmlNodePtr));
3787 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003788 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003789 return(NULL);
3790 }
3791 val1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08003792 val1->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003793 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003794 if (n2->type == XML_NAMESPACE_DECL) {
3795 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003796
3797 val1->nodeTab[val1->nodeNr++] =
3798 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3799 } else
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003800 val1->nodeTab[val1->nodeNr++] = n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003801 }
3802
3803 return(val1);
3804}
3805
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003806#if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
Owen Taylor3473f882001-02-23 17:55:21 +00003807/**
Daniel Veillard75be0132002-03-13 10:03:35 +00003808 * xmlXPathNodeSetMergeUnique:
3809 * @val1: the first NodeSet or NULL
3810 * @val2: the second NodeSet
3811 *
3812 * Merges two nodesets, all nodes from @val2 are added to @val1
3813 * if @val1 is NULL, a new set is created and copied from @val2
3814 *
3815 * Returns @val1 once extended or NULL in case of error.
3816 */
3817static xmlNodeSetPtr
3818xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00003819 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00003820
3821 if (val2 == NULL) return(val1);
3822 if (val1 == NULL) {
3823 val1 = xmlXPathNodeSetCreate(NULL);
3824 }
Daniel Veillardf88d8492008-04-01 08:00:31 +00003825 if (val1 == NULL)
3826 return (NULL);
Daniel Veillard75be0132002-03-13 10:03:35 +00003827
William M. Brack08171912003-12-29 02:52:11 +00003828 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00003829
3830 for (i = 0;i < val2->nodeNr;i++) {
3831 /*
3832 * grow the nodeTab if needed
3833 */
3834 if (val1->nodeMax == 0) {
3835 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3836 sizeof(xmlNodePtr));
3837 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003838 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00003839 return(NULL);
3840 }
3841 memset(val1->nodeTab, 0 ,
3842 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3843 val1->nodeMax = XML_NODESET_DEFAULT;
3844 } else if (val1->nodeNr == val1->nodeMax) {
3845 xmlNodePtr *temp;
3846
3847 val1->nodeMax *= 2;
3848 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3849 sizeof(xmlNodePtr));
3850 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003851 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00003852 return(NULL);
3853 }
3854 val1->nodeTab = temp;
3855 }
3856 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3857 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
3858
3859 val1->nodeTab[val1->nodeNr++] =
3860 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3861 } else
3862 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
3863 }
3864
3865 return(val1);
3866}
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003867#endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3868
3869/**
3870 * xmlXPathNodeSetMergeAndClear:
3871 * @set1: the first NodeSet or NULL
3872 * @set2: the second NodeSet
3873 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3874 *
3875 * Merges two nodesets, all nodes from @set2 are added to @set1
3876 * if @set1 is NULL, a new set is created and copied from @set2.
3877 * Checks for duplicate nodes. Clears set2.
3878 *
3879 * Returns @set1 once extended or NULL in case of error.
3880 */
3881static xmlNodeSetPtr
3882xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3883 int hasNullEntries)
3884{
3885 if ((set1 == NULL) && (hasNullEntries == 0)) {
3886 /*
3887 * Note that doing a memcpy of the list, namespace nodes are
3888 * just assigned to set1, since set2 is cleared anyway.
3889 */
3890 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3891 if (set1 == NULL)
3892 return(NULL);
3893 if (set2->nodeNr != 0) {
3894 memcpy(set1->nodeTab, set2->nodeTab,
3895 set2->nodeNr * sizeof(xmlNodePtr));
3896 set1->nodeNr = set2->nodeNr;
3897 }
3898 } else {
3899 int i, j, initNbSet1;
3900 xmlNodePtr n1, n2;
3901
3902 if (set1 == NULL)
Daniel Veillardf88d8492008-04-01 08:00:31 +00003903 set1 = xmlXPathNodeSetCreate(NULL);
3904 if (set1 == NULL)
3905 return (NULL);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003906
Daniel Veillard45490ae2008-07-29 09:13:19 +00003907 initNbSet1 = set1->nodeNr;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003908 for (i = 0;i < set2->nodeNr;i++) {
3909 n2 = set2->nodeTab[i];
3910 /*
3911 * Skip NULLed entries.
3912 */
3913 if (n2 == NULL)
3914 continue;
3915 /*
3916 * Skip duplicates.
3917 */
3918 for (j = 0; j < initNbSet1; j++) {
3919 n1 = set1->nodeTab[j];
Daniel Veillard45490ae2008-07-29 09:13:19 +00003920 if (n1 == n2) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003921 goto skip_node;
3922 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3923 (n2->type == XML_NAMESPACE_DECL))
Daniel Veillard45490ae2008-07-29 09:13:19 +00003924 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003925 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3926 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3927 ((xmlNsPtr) n2)->prefix)))
3928 {
3929 /*
3930 * Free the namespace node.
3931 */
3932 set2->nodeTab[i] = NULL;
3933 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3934 goto skip_node;
3935 }
3936 }
3937 }
3938 /*
3939 * grow the nodeTab if needed
3940 */
3941 if (set1->nodeMax == 0) {
3942 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3943 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3944 if (set1->nodeTab == NULL) {
3945 xmlXPathErrMemory(NULL, "merging nodeset\n");
3946 return(NULL);
3947 }
3948 memset(set1->nodeTab, 0,
3949 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3950 set1->nodeMax = XML_NODESET_DEFAULT;
3951 } else if (set1->nodeNr >= set1->nodeMax) {
3952 xmlNodePtr *temp;
Daniel Veillard45490ae2008-07-29 09:13:19 +00003953
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003954 temp = (xmlNodePtr *) xmlRealloc(
Chris Evansd7958b22011-03-23 08:13:06 +08003955 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003956 if (temp == NULL) {
3957 xmlXPathErrMemory(NULL, "merging nodeset\n");
3958 return(NULL);
3959 }
3960 set1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08003961 set1->nodeMax *= 2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003962 }
3963 if (n2->type == XML_NAMESPACE_DECL) {
3964 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard45490ae2008-07-29 09:13:19 +00003965
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003966 set1->nodeTab[set1->nodeNr++] =
3967 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3968 } else
3969 set1->nodeTab[set1->nodeNr++] = n2;
3970skip_node:
3971 {}
3972 }
3973 }
3974 set2->nodeNr = 0;
3975 return(set1);
3976}
3977
3978/**
3979 * xmlXPathNodeSetMergeAndClearNoDupls:
3980 * @set1: the first NodeSet or NULL
3981 * @set2: the second NodeSet
3982 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3983 *
3984 * Merges two nodesets, all nodes from @set2 are added to @set1
3985 * if @set1 is NULL, a new set is created and copied from @set2.
3986 * Doesn't chack for duplicate nodes. Clears set2.
3987 *
3988 * Returns @set1 once extended or NULL in case of error.
3989 */
3990static xmlNodeSetPtr
3991xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3992 int hasNullEntries)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003993{
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003994 if (set2 == NULL)
3995 return(set1);
3996 if ((set1 == NULL) && (hasNullEntries == 0)) {
3997 /*
3998 * Note that doing a memcpy of the list, namespace nodes are
3999 * just assigned to set1, since set2 is cleared anyway.
4000 */
4001 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
4002 if (set1 == NULL)
4003 return(NULL);
4004 if (set2->nodeNr != 0) {
4005 memcpy(set1->nodeTab, set2->nodeTab,
4006 set2->nodeNr * sizeof(xmlNodePtr));
4007 set1->nodeNr = set2->nodeNr;
4008 }
4009 } else {
4010 int i;
4011 xmlNodePtr n2;
4012
4013 if (set1 == NULL)
4014 set1 = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004015 if (set1 == NULL)
4016 return (NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004017
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004018 for (i = 0;i < set2->nodeNr;i++) {
4019 n2 = set2->nodeTab[i];
4020 /*
4021 * Skip NULLed entries.
4022 */
4023 if (n2 == NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004024 continue;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004025 if (set1->nodeMax == 0) {
4026 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4027 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4028 if (set1->nodeTab == NULL) {
4029 xmlXPathErrMemory(NULL, "merging nodeset\n");
4030 return(NULL);
4031 }
4032 memset(set1->nodeTab, 0,
4033 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4034 set1->nodeMax = XML_NODESET_DEFAULT;
4035 } else if (set1->nodeNr >= set1->nodeMax) {
4036 xmlNodePtr *temp;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004037
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004038 temp = (xmlNodePtr *) xmlRealloc(
Chris Evansd7958b22011-03-23 08:13:06 +08004039 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004040 if (temp == NULL) {
4041 xmlXPathErrMemory(NULL, "merging nodeset\n");
4042 return(NULL);
4043 }
4044 set1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08004045 set1->nodeMax *= 2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004046 }
4047 set1->nodeTab[set1->nodeNr++] = n2;
4048 }
4049 }
4050 set2->nodeNr = 0;
4051 return(set1);
4052}
Daniel Veillard75be0132002-03-13 10:03:35 +00004053
4054/**
Owen Taylor3473f882001-02-23 17:55:21 +00004055 * xmlXPathNodeSetDel:
4056 * @cur: the initial node set
4057 * @val: an xmlNodePtr
4058 *
4059 * Removes an xmlNodePtr from an existing NodeSet
4060 */
4061void
4062xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4063 int i;
4064
4065 if (cur == NULL) return;
4066 if (val == NULL) return;
4067
4068 /*
William M. Brack08171912003-12-29 02:52:11 +00004069 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00004070 */
4071 for (i = 0;i < cur->nodeNr;i++)
4072 if (cur->nodeTab[i] == val) break;
4073
William M. Brack08171912003-12-29 02:52:11 +00004074 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00004075#ifdef DEBUG
Daniel Veillard45490ae2008-07-29 09:13:19 +00004076 xmlGenericError(xmlGenericErrorContext,
Owen Taylor3473f882001-02-23 17:55:21 +00004077 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4078 val->name);
4079#endif
4080 return;
4081 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004082 if ((cur->nodeTab[i] != NULL) &&
4083 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4084 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004085 cur->nodeNr--;
4086 for (;i < cur->nodeNr;i++)
4087 cur->nodeTab[i] = cur->nodeTab[i + 1];
4088 cur->nodeTab[cur->nodeNr] = NULL;
4089}
4090
4091/**
4092 * xmlXPathNodeSetRemove:
4093 * @cur: the initial node set
4094 * @val: the index to remove
4095 *
4096 * Removes an entry from an existing NodeSet list.
4097 */
4098void
4099xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4100 if (cur == NULL) return;
4101 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004102 if ((cur->nodeTab[val] != NULL) &&
4103 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4104 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00004105 cur->nodeNr--;
4106 for (;val < cur->nodeNr;val++)
4107 cur->nodeTab[val] = cur->nodeTab[val + 1];
4108 cur->nodeTab[cur->nodeNr] = NULL;
4109}
4110
4111/**
4112 * xmlXPathFreeNodeSet:
4113 * @obj: the xmlNodeSetPtr to free
4114 *
4115 * Free the NodeSet compound (not the actual nodes !).
4116 */
4117void
4118xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4119 if (obj == NULL) return;
4120 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004121 int i;
4122
William M. Brack08171912003-12-29 02:52:11 +00004123 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004124 for (i = 0;i < obj->nodeNr;i++)
4125 if ((obj->nodeTab[i] != NULL) &&
4126 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4127 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004128 xmlFree(obj->nodeTab);
4129 }
Owen Taylor3473f882001-02-23 17:55:21 +00004130 xmlFree(obj);
4131}
4132
4133/**
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004134 * xmlXPathNodeSetClear:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004135 * @set: the node set to clear
Daniel Veillard45490ae2008-07-29 09:13:19 +00004136 *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004137 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4138 * are feed), but does *not* free the list itself. Sets the length of the
4139 * list to 0.
4140 */
4141static void
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004142xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4143{
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004144 if ((set == NULL) || (set->nodeNr <= 0))
4145 return;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004146 else if (hasNsNodes) {
4147 int i;
4148 xmlNodePtr node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004149
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004150 for (i = 0; i < set->nodeNr; i++) {
4151 node = set->nodeTab[i];
4152 if ((node != NULL) &&
4153 (node->type == XML_NAMESPACE_DECL))
4154 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004155 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004156 }
4157 set->nodeNr = 0;
4158}
4159
4160/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004161 * xmlXPathNodeSetClearFromPos:
4162 * @set: the node set to be cleared
4163 * @pos: the start position to clear from
Daniel Veillard45490ae2008-07-29 09:13:19 +00004164 *
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004165 * Clears the list from temporary XPath objects (e.g. namespace nodes
4166 * are feed) starting with the entry at @pos, but does *not* free the list
4167 * itself. Sets the length of the list to @pos.
4168 */
4169static void
4170xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4171{
4172 if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4173 return;
4174 else if ((hasNsNodes)) {
4175 int i;
4176 xmlNodePtr node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004177
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004178 for (i = pos; i < set->nodeNr; i++) {
4179 node = set->nodeTab[i];
4180 if ((node != NULL) &&
4181 (node->type == XML_NAMESPACE_DECL))
4182 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004183 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004184 }
4185 set->nodeNr = pos;
4186}
4187
4188/**
Owen Taylor3473f882001-02-23 17:55:21 +00004189 * xmlXPathFreeValueTree:
4190 * @obj: the xmlNodeSetPtr to free
4191 *
4192 * Free the NodeSet compound and the actual tree, this is different
4193 * from xmlXPathFreeNodeSet()
4194 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004195static void
Owen Taylor3473f882001-02-23 17:55:21 +00004196xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4197 int i;
4198
4199 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00004200
4201 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004202 for (i = 0;i < obj->nodeNr;i++) {
4203 if (obj->nodeTab[i] != NULL) {
4204 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4205 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4206 } else {
4207 xmlFreeNodeList(obj->nodeTab[i]);
4208 }
4209 }
4210 }
Owen Taylor3473f882001-02-23 17:55:21 +00004211 xmlFree(obj->nodeTab);
4212 }
Owen Taylor3473f882001-02-23 17:55:21 +00004213 xmlFree(obj);
4214}
4215
4216#if defined(DEBUG) || defined(DEBUG_STEP)
4217/**
4218 * xmlGenericErrorContextNodeSet:
4219 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00004220 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00004221 *
4222 * Quick display of a NodeSet
4223 */
4224void
4225xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4226 int i;
4227
4228 if (output == NULL) output = xmlGenericErrorContext;
4229 if (obj == NULL) {
4230 fprintf(output, "NodeSet == NULL !\n");
4231 return;
4232 }
4233 if (obj->nodeNr == 0) {
4234 fprintf(output, "NodeSet is empty\n");
4235 return;
4236 }
4237 if (obj->nodeTab == NULL) {
4238 fprintf(output, " nodeTab == NULL !\n");
4239 return;
4240 }
4241 for (i = 0; i < obj->nodeNr; i++) {
4242 if (obj->nodeTab[i] == NULL) {
4243 fprintf(output, " NULL !\n");
4244 return;
4245 }
4246 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4247 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4248 fprintf(output, " /");
4249 else if (obj->nodeTab[i]->name == NULL)
4250 fprintf(output, " noname!");
4251 else fprintf(output, " %s", obj->nodeTab[i]->name);
4252 }
4253 fprintf(output, "\n");
4254}
4255#endif
4256
4257/**
4258 * xmlXPathNewNodeSet:
4259 * @val: the NodePtr value
4260 *
4261 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4262 * it with the single Node @val
4263 *
4264 * Returns the newly created object.
4265 */
4266xmlXPathObjectPtr
4267xmlXPathNewNodeSet(xmlNodePtr val) {
4268 xmlXPathObjectPtr ret;
4269
4270 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4271 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004272 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004273 return(NULL);
4274 }
4275 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4276 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00004277 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004278 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00004279 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004280#ifdef XP_DEBUG_OBJ_USAGE
4281 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4282#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004283 return(ret);
4284}
4285
4286/**
4287 * xmlXPathNewValueTree:
4288 * @val: the NodePtr value
4289 *
4290 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4291 * it with the tree root @val
4292 *
4293 * Returns the newly created object.
4294 */
4295xmlXPathObjectPtr
4296xmlXPathNewValueTree(xmlNodePtr val) {
4297 xmlXPathObjectPtr ret;
4298
4299 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4300 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004301 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004302 return(NULL);
4303 }
4304 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4305 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00004306 ret->boolval = 1;
4307 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00004308 ret->nodesetval = xmlXPathNodeSetCreate(val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004309#ifdef XP_DEBUG_OBJ_USAGE
4310 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4311#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004312 return(ret);
4313}
4314
4315/**
4316 * xmlXPathNewNodeSetList:
4317 * @val: an existing NodeSet
4318 *
4319 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4320 * it with the Nodeset @val
4321 *
4322 * Returns the newly created object.
4323 */
4324xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004325xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4326{
Owen Taylor3473f882001-02-23 17:55:21 +00004327 xmlXPathObjectPtr ret;
4328 int i;
4329
4330 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004331 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00004332 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004333 ret = xmlXPathNewNodeSet(NULL);
4334 else {
4335 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004336 if (ret)
4337 for (i = 1; i < val->nodeNr; ++i)
4338 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004339 }
Owen Taylor3473f882001-02-23 17:55:21 +00004340
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004341 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004342}
4343
4344/**
4345 * xmlXPathWrapNodeSet:
4346 * @val: the NodePtr value
4347 *
4348 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4349 *
4350 * Returns the newly created object.
4351 */
4352xmlXPathObjectPtr
4353xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4354 xmlXPathObjectPtr ret;
4355
4356 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4357 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004358 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004359 return(NULL);
4360 }
4361 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4362 ret->type = XPATH_NODESET;
4363 ret->nodesetval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004364#ifdef XP_DEBUG_OBJ_USAGE
4365 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4366#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004367 return(ret);
4368}
4369
4370/**
4371 * xmlXPathFreeNodeSetList:
4372 * @obj: an existing NodeSetList object
4373 *
4374 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4375 * the list contrary to xmlXPathFreeObject().
4376 */
4377void
4378xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4379 if (obj == NULL) return;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004380#ifdef XP_DEBUG_OBJ_USAGE
4381 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4382#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004383 xmlFree(obj);
4384}
4385
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004386/**
4387 * xmlXPathDifference:
4388 * @nodes1: a node-set
4389 * @nodes2: a node-set
4390 *
4391 * Implements the EXSLT - Sets difference() function:
4392 * node-set set:difference (node-set, node-set)
4393 *
4394 * Returns the difference between the two node sets, or nodes1 if
4395 * nodes2 is empty
4396 */
4397xmlNodeSetPtr
4398xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4399 xmlNodeSetPtr ret;
4400 int i, l1;
4401 xmlNodePtr cur;
4402
4403 if (xmlXPathNodeSetIsEmpty(nodes2))
4404 return(nodes1);
4405
4406 ret = xmlXPathNodeSetCreate(NULL);
4407 if (xmlXPathNodeSetIsEmpty(nodes1))
4408 return(ret);
4409
4410 l1 = xmlXPathNodeSetGetLength(nodes1);
4411
4412 for (i = 0; i < l1; i++) {
4413 cur = xmlXPathNodeSetItem(nodes1, i);
4414 if (!xmlXPathNodeSetContains(nodes2, cur))
4415 xmlXPathNodeSetAddUnique(ret, cur);
4416 }
4417 return(ret);
4418}
4419
4420/**
4421 * xmlXPathIntersection:
4422 * @nodes1: a node-set
4423 * @nodes2: a node-set
4424 *
4425 * Implements the EXSLT - Sets intersection() function:
4426 * node-set set:intersection (node-set, node-set)
4427 *
4428 * Returns a node set comprising the nodes that are within both the
4429 * node sets passed as arguments
4430 */
4431xmlNodeSetPtr
4432xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4433 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4434 int i, l1;
4435 xmlNodePtr cur;
4436
Daniel Veillardf88d8492008-04-01 08:00:31 +00004437 if (ret == NULL)
4438 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004439 if (xmlXPathNodeSetIsEmpty(nodes1))
4440 return(ret);
4441 if (xmlXPathNodeSetIsEmpty(nodes2))
4442 return(ret);
4443
4444 l1 = xmlXPathNodeSetGetLength(nodes1);
4445
4446 for (i = 0; i < l1; i++) {
4447 cur = xmlXPathNodeSetItem(nodes1, i);
4448 if (xmlXPathNodeSetContains(nodes2, cur))
4449 xmlXPathNodeSetAddUnique(ret, cur);
4450 }
4451 return(ret);
4452}
4453
4454/**
4455 * xmlXPathDistinctSorted:
4456 * @nodes: a node-set, sorted by document order
4457 *
4458 * Implements the EXSLT - Sets distinct() function:
4459 * node-set set:distinct (node-set)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004460 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004461 * Returns a subset of the nodes contained in @nodes, or @nodes if
4462 * it is empty
4463 */
4464xmlNodeSetPtr
4465xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4466 xmlNodeSetPtr ret;
4467 xmlHashTablePtr hash;
4468 int i, l;
4469 xmlChar * strval;
4470 xmlNodePtr cur;
4471
4472 if (xmlXPathNodeSetIsEmpty(nodes))
4473 return(nodes);
4474
4475 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004476 if (ret == NULL)
4477 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004478 l = xmlXPathNodeSetGetLength(nodes);
4479 hash = xmlHashCreate (l);
4480 for (i = 0; i < l; i++) {
4481 cur = xmlXPathNodeSetItem(nodes, i);
4482 strval = xmlXPathCastNodeToString(cur);
4483 if (xmlHashLookup(hash, strval) == NULL) {
4484 xmlHashAddEntry(hash, strval, strval);
4485 xmlXPathNodeSetAddUnique(ret, cur);
4486 } else {
4487 xmlFree(strval);
4488 }
4489 }
4490 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4491 return(ret);
4492}
4493
4494/**
4495 * xmlXPathDistinct:
4496 * @nodes: a node-set
4497 *
4498 * Implements the EXSLT - Sets distinct() function:
4499 * node-set set:distinct (node-set)
4500 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4501 * is called with the sorted node-set
4502 *
4503 * Returns a subset of the nodes contained in @nodes, or @nodes if
4504 * it is empty
4505 */
4506xmlNodeSetPtr
4507xmlXPathDistinct (xmlNodeSetPtr nodes) {
4508 if (xmlXPathNodeSetIsEmpty(nodes))
4509 return(nodes);
4510
4511 xmlXPathNodeSetSort(nodes);
4512 return(xmlXPathDistinctSorted(nodes));
4513}
4514
4515/**
4516 * xmlXPathHasSameNodes:
4517 * @nodes1: a node-set
4518 * @nodes2: a node-set
4519 *
4520 * Implements the EXSLT - Sets has-same-nodes function:
4521 * boolean set:has-same-node(node-set, node-set)
4522 *
4523 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4524 * otherwise
4525 */
4526int
4527xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4528 int i, l;
4529 xmlNodePtr cur;
4530
4531 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4532 xmlXPathNodeSetIsEmpty(nodes2))
4533 return(0);
4534
4535 l = xmlXPathNodeSetGetLength(nodes1);
4536 for (i = 0; i < l; i++) {
4537 cur = xmlXPathNodeSetItem(nodes1, i);
4538 if (xmlXPathNodeSetContains(nodes2, cur))
4539 return(1);
4540 }
4541 return(0);
4542}
4543
4544/**
4545 * xmlXPathNodeLeadingSorted:
4546 * @nodes: a node-set, sorted by document order
4547 * @node: a node
4548 *
4549 * Implements the EXSLT - Sets leading() function:
4550 * node-set set:leading (node-set, node-set)
4551 *
4552 * Returns the nodes in @nodes that precede @node in document order,
4553 * @nodes if @node is NULL or an empty node-set if @nodes
4554 * doesn't contain @node
4555 */
4556xmlNodeSetPtr
4557xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4558 int i, l;
4559 xmlNodePtr cur;
4560 xmlNodeSetPtr ret;
4561
4562 if (node == NULL)
4563 return(nodes);
4564
4565 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004566 if (ret == NULL)
4567 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004568 if (xmlXPathNodeSetIsEmpty(nodes) ||
4569 (!xmlXPathNodeSetContains(nodes, node)))
4570 return(ret);
4571
4572 l = xmlXPathNodeSetGetLength(nodes);
4573 for (i = 0; i < l; i++) {
4574 cur = xmlXPathNodeSetItem(nodes, i);
4575 if (cur == node)
4576 break;
4577 xmlXPathNodeSetAddUnique(ret, cur);
4578 }
4579 return(ret);
4580}
4581
4582/**
4583 * xmlXPathNodeLeading:
4584 * @nodes: a node-set
4585 * @node: a node
4586 *
4587 * Implements the EXSLT - Sets leading() function:
4588 * node-set set:leading (node-set, node-set)
4589 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4590 * is called.
4591 *
4592 * Returns the nodes in @nodes that precede @node in document order,
4593 * @nodes if @node is NULL or an empty node-set if @nodes
4594 * doesn't contain @node
4595 */
4596xmlNodeSetPtr
4597xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4598 xmlXPathNodeSetSort(nodes);
4599 return(xmlXPathNodeLeadingSorted(nodes, node));
4600}
4601
4602/**
4603 * xmlXPathLeadingSorted:
4604 * @nodes1: a node-set, sorted by document order
4605 * @nodes2: a node-set, sorted by document order
4606 *
4607 * Implements the EXSLT - Sets leading() function:
4608 * node-set set:leading (node-set, node-set)
4609 *
4610 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4611 * in document order, @nodes1 if @nodes2 is NULL or empty or
4612 * an empty node-set if @nodes1 doesn't contain @nodes2
4613 */
4614xmlNodeSetPtr
4615xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4616 if (xmlXPathNodeSetIsEmpty(nodes2))
4617 return(nodes1);
4618 return(xmlXPathNodeLeadingSorted(nodes1,
4619 xmlXPathNodeSetItem(nodes2, 1)));
4620}
4621
4622/**
4623 * xmlXPathLeading:
4624 * @nodes1: a node-set
4625 * @nodes2: a node-set
4626 *
4627 * Implements the EXSLT - Sets leading() function:
4628 * node-set set:leading (node-set, node-set)
4629 * @nodes1 and @nodes2 are sorted by document order, then
4630 * #exslSetsLeadingSorted is called.
4631 *
4632 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4633 * in document order, @nodes1 if @nodes2 is NULL or empty or
4634 * an empty node-set if @nodes1 doesn't contain @nodes2
4635 */
4636xmlNodeSetPtr
4637xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4638 if (xmlXPathNodeSetIsEmpty(nodes2))
4639 return(nodes1);
4640 if (xmlXPathNodeSetIsEmpty(nodes1))
4641 return(xmlXPathNodeSetCreate(NULL));
4642 xmlXPathNodeSetSort(nodes1);
4643 xmlXPathNodeSetSort(nodes2);
4644 return(xmlXPathNodeLeadingSorted(nodes1,
4645 xmlXPathNodeSetItem(nodes2, 1)));
4646}
4647
4648/**
4649 * xmlXPathNodeTrailingSorted:
4650 * @nodes: a node-set, sorted by document order
4651 * @node: a node
4652 *
4653 * Implements the EXSLT - Sets trailing() function:
4654 * node-set set:trailing (node-set, node-set)
4655 *
4656 * Returns the nodes in @nodes that follow @node in document order,
4657 * @nodes if @node is NULL or an empty node-set if @nodes
4658 * doesn't contain @node
4659 */
4660xmlNodeSetPtr
4661xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4662 int i, l;
4663 xmlNodePtr cur;
4664 xmlNodeSetPtr ret;
4665
4666 if (node == NULL)
4667 return(nodes);
4668
4669 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004670 if (ret == NULL)
4671 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004672 if (xmlXPathNodeSetIsEmpty(nodes) ||
4673 (!xmlXPathNodeSetContains(nodes, node)))
4674 return(ret);
4675
4676 l = xmlXPathNodeSetGetLength(nodes);
William M. Brack97ac8192007-06-06 17:19:24 +00004677 for (i = l - 1; i >= 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004678 cur = xmlXPathNodeSetItem(nodes, i);
4679 if (cur == node)
4680 break;
4681 xmlXPathNodeSetAddUnique(ret, cur);
4682 }
William M. Brack97ac8192007-06-06 17:19:24 +00004683 xmlXPathNodeSetSort(ret); /* bug 413451 */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004684 return(ret);
4685}
4686
4687/**
4688 * xmlXPathNodeTrailing:
4689 * @nodes: a node-set
4690 * @node: a node
4691 *
4692 * Implements the EXSLT - Sets trailing() function:
4693 * node-set set:trailing (node-set, node-set)
4694 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4695 * is called.
4696 *
4697 * Returns the nodes in @nodes that follow @node in document order,
4698 * @nodes if @node is NULL or an empty node-set if @nodes
4699 * doesn't contain @node
4700 */
4701xmlNodeSetPtr
4702xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4703 xmlXPathNodeSetSort(nodes);
4704 return(xmlXPathNodeTrailingSorted(nodes, node));
4705}
4706
4707/**
4708 * xmlXPathTrailingSorted:
4709 * @nodes1: a node-set, sorted by document order
4710 * @nodes2: a node-set, sorted by document order
4711 *
4712 * Implements the EXSLT - Sets trailing() function:
4713 * node-set set:trailing (node-set, node-set)
4714 *
4715 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4716 * in document order, @nodes1 if @nodes2 is NULL or empty or
4717 * an empty node-set if @nodes1 doesn't contain @nodes2
4718 */
4719xmlNodeSetPtr
4720xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4721 if (xmlXPathNodeSetIsEmpty(nodes2))
4722 return(nodes1);
4723 return(xmlXPathNodeTrailingSorted(nodes1,
4724 xmlXPathNodeSetItem(nodes2, 0)));
4725}
4726
4727/**
4728 * xmlXPathTrailing:
4729 * @nodes1: a node-set
4730 * @nodes2: a node-set
4731 *
4732 * Implements the EXSLT - Sets trailing() function:
4733 * node-set set:trailing (node-set, node-set)
4734 * @nodes1 and @nodes2 are sorted by document order, then
4735 * #xmlXPathTrailingSorted is called.
4736 *
4737 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4738 * in document order, @nodes1 if @nodes2 is NULL or empty or
4739 * an empty node-set if @nodes1 doesn't contain @nodes2
4740 */
4741xmlNodeSetPtr
4742xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4743 if (xmlXPathNodeSetIsEmpty(nodes2))
4744 return(nodes1);
4745 if (xmlXPathNodeSetIsEmpty(nodes1))
4746 return(xmlXPathNodeSetCreate(NULL));
4747 xmlXPathNodeSetSort(nodes1);
4748 xmlXPathNodeSetSort(nodes2);
4749 return(xmlXPathNodeTrailingSorted(nodes1,
4750 xmlXPathNodeSetItem(nodes2, 0)));
4751}
4752
Owen Taylor3473f882001-02-23 17:55:21 +00004753/************************************************************************
4754 * *
4755 * Routines to handle extra functions *
4756 * *
4757 ************************************************************************/
4758
4759/**
4760 * xmlXPathRegisterFunc:
4761 * @ctxt: the XPath context
4762 * @name: the function name
4763 * @f: the function implementation or NULL
4764 *
4765 * Register a new function. If @f is NULL it unregisters the function
4766 *
4767 * Returns 0 in case of success, -1 in case of error
4768 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00004769int
Owen Taylor3473f882001-02-23 17:55:21 +00004770xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4771 xmlXPathFunction f) {
4772 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4773}
4774
4775/**
4776 * xmlXPathRegisterFuncNS:
4777 * @ctxt: the XPath context
4778 * @name: the function name
4779 * @ns_uri: the function namespace URI
4780 * @f: the function implementation or NULL
4781 *
4782 * Register a new function. If @f is NULL it unregisters the function
4783 *
4784 * Returns 0 in case of success, -1 in case of error
4785 */
4786int
4787xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4788 const xmlChar *ns_uri, xmlXPathFunction f) {
4789 if (ctxt == NULL)
4790 return(-1);
4791 if (name == NULL)
4792 return(-1);
4793
4794 if (ctxt->funcHash == NULL)
4795 ctxt->funcHash = xmlHashCreate(0);
4796 if (ctxt->funcHash == NULL)
4797 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004798 if (f == NULL)
4799 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
William M. Brackad0e67c2004-12-01 14:35:10 +00004800 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
Owen Taylor3473f882001-02-23 17:55:21 +00004801}
4802
4803/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00004804 * xmlXPathRegisterFuncLookup:
4805 * @ctxt: the XPath context
4806 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004807 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00004808 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004809 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00004810 */
4811void
4812xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4813 xmlXPathFuncLookupFunc f,
4814 void *funcCtxt) {
4815 if (ctxt == NULL)
4816 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004817 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004818 ctxt->funcLookupData = funcCtxt;
4819}
4820
4821/**
Owen Taylor3473f882001-02-23 17:55:21 +00004822 * xmlXPathFunctionLookup:
4823 * @ctxt: the XPath context
4824 * @name: the function name
4825 *
4826 * Search in the Function array of the context for the given
4827 * function.
4828 *
4829 * Returns the xmlXPathFunction or NULL if not found
4830 */
4831xmlXPathFunction
4832xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00004833 if (ctxt == NULL)
4834 return (NULL);
4835
4836 if (ctxt->funcLookupFunc != NULL) {
4837 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004838 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004839
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004840 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004841 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004842 if (ret != NULL)
4843 return(ret);
4844 }
Owen Taylor3473f882001-02-23 17:55:21 +00004845 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4846}
4847
4848/**
4849 * xmlXPathFunctionLookupNS:
4850 * @ctxt: the XPath context
4851 * @name: the function name
4852 * @ns_uri: the function namespace URI
4853 *
4854 * Search in the Function array of the context for the given
4855 * function.
4856 *
4857 * Returns the xmlXPathFunction or NULL if not found
4858 */
4859xmlXPathFunction
4860xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4861 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00004862 xmlXPathFunction ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004863
Owen Taylor3473f882001-02-23 17:55:21 +00004864 if (ctxt == NULL)
4865 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004866 if (name == NULL)
4867 return(NULL);
4868
Thomas Broyerba4ad322001-07-26 16:55:21 +00004869 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004870 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004871
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004872 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004873 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004874 if (ret != NULL)
4875 return(ret);
4876 }
4877
4878 if (ctxt->funcHash == NULL)
4879 return(NULL);
4880
William M. Brackad0e67c2004-12-01 14:35:10 +00004881 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4882 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004883}
4884
4885/**
4886 * xmlXPathRegisteredFuncsCleanup:
4887 * @ctxt: the XPath context
4888 *
4889 * Cleanup the XPath context data associated to registered functions
4890 */
4891void
4892xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4893 if (ctxt == NULL)
4894 return;
4895
4896 xmlHashFree(ctxt->funcHash, NULL);
4897 ctxt->funcHash = NULL;
4898}
4899
4900/************************************************************************
4901 * *
William M. Brack08171912003-12-29 02:52:11 +00004902 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00004903 * *
4904 ************************************************************************/
4905
4906/**
4907 * xmlXPathRegisterVariable:
4908 * @ctxt: the XPath context
4909 * @name: the variable name
4910 * @value: the variable value or NULL
4911 *
4912 * Register a new variable value. If @value is NULL it unregisters
4913 * the variable
4914 *
4915 * Returns 0 in case of success, -1 in case of error
4916 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00004917int
Owen Taylor3473f882001-02-23 17:55:21 +00004918xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4919 xmlXPathObjectPtr value) {
4920 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4921}
4922
4923/**
4924 * xmlXPathRegisterVariableNS:
4925 * @ctxt: the XPath context
4926 * @name: the variable name
4927 * @ns_uri: the variable namespace URI
4928 * @value: the variable value or NULL
4929 *
4930 * Register a new variable value. If @value is NULL it unregisters
4931 * the variable
4932 *
4933 * Returns 0 in case of success, -1 in case of error
4934 */
4935int
4936xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4937 const xmlChar *ns_uri,
4938 xmlXPathObjectPtr value) {
4939 if (ctxt == NULL)
4940 return(-1);
4941 if (name == NULL)
4942 return(-1);
4943
4944 if (ctxt->varHash == NULL)
4945 ctxt->varHash = xmlHashCreate(0);
4946 if (ctxt->varHash == NULL)
4947 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004948 if (value == NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004949 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
Daniel Veillard94394cd2003-10-29 17:07:51 +00004950 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00004951 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4952 (void *) value,
4953 (xmlHashDeallocator)xmlXPathFreeObject));
4954}
4955
4956/**
4957 * xmlXPathRegisterVariableLookup:
4958 * @ctxt: the XPath context
4959 * @f: the lookup function
4960 * @data: the lookup data
4961 *
4962 * register an external mechanism to do variable lookup
4963 */
4964void
4965xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4966 xmlXPathVariableLookupFunc f, void *data) {
4967 if (ctxt == NULL)
4968 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004969 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00004970 ctxt->varLookupData = data;
4971}
4972
4973/**
4974 * xmlXPathVariableLookup:
4975 * @ctxt: the XPath context
4976 * @name: the variable name
4977 *
4978 * Search in the Variable array of the context for the given
4979 * variable value.
4980 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00004981 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00004982 */
4983xmlXPathObjectPtr
4984xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4985 if (ctxt == NULL)
4986 return(NULL);
4987
4988 if (ctxt->varLookupFunc != NULL) {
4989 xmlXPathObjectPtr ret;
4990
4991 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4992 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00004993 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004994 }
4995 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4996}
4997
4998/**
4999 * xmlXPathVariableLookupNS:
5000 * @ctxt: the XPath context
5001 * @name: the variable name
5002 * @ns_uri: the variable namespace URI
5003 *
5004 * Search in the Variable array of the context for the given
Daniel Veillard45490ae2008-07-29 09:13:19 +00005005 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00005006 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00005007 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00005008 */
5009xmlXPathObjectPtr
5010xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5011 const xmlChar *ns_uri) {
5012 if (ctxt == NULL)
5013 return(NULL);
5014
5015 if (ctxt->varLookupFunc != NULL) {
5016 xmlXPathObjectPtr ret;
5017
5018 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5019 (ctxt->varLookupData, name, ns_uri);
5020 if (ret != NULL) return(ret);
5021 }
5022
5023 if (ctxt->varHash == NULL)
5024 return(NULL);
5025 if (name == NULL)
5026 return(NULL);
5027
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005028 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
Daniel Veillard8c357d52001-07-03 23:43:33 +00005029 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00005030}
5031
5032/**
5033 * xmlXPathRegisteredVariablesCleanup:
5034 * @ctxt: the XPath context
5035 *
5036 * Cleanup the XPath context data associated to registered variables
5037 */
5038void
5039xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5040 if (ctxt == NULL)
5041 return;
5042
Daniel Veillard76d66f42001-05-16 21:05:17 +00005043 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00005044 ctxt->varHash = NULL;
5045}
5046
5047/**
5048 * xmlXPathRegisterNs:
5049 * @ctxt: the XPath context
Daniel Veillarddb3ce962009-03-25 09:43:49 +00005050 * @prefix: the namespace prefix cannot be NULL or empty string
Owen Taylor3473f882001-02-23 17:55:21 +00005051 * @ns_uri: the namespace name
5052 *
5053 * Register a new namespace. If @ns_uri is NULL it unregisters
5054 * the namespace
5055 *
5056 * Returns 0 in case of success, -1 in case of error
5057 */
5058int
5059xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5060 const xmlChar *ns_uri) {
5061 if (ctxt == NULL)
5062 return(-1);
5063 if (prefix == NULL)
5064 return(-1);
Daniel Veillarddb3ce962009-03-25 09:43:49 +00005065 if (prefix[0] == 0)
5066 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00005067
5068 if (ctxt->nsHash == NULL)
5069 ctxt->nsHash = xmlHashCreate(10);
5070 if (ctxt->nsHash == NULL)
5071 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00005072 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00005073 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00005074 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00005075 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00005076 (xmlHashDeallocator)xmlFree));
5077}
5078
5079/**
5080 * xmlXPathNsLookup:
5081 * @ctxt: the XPath context
5082 * @prefix: the namespace prefix value
5083 *
5084 * Search in the namespace declaration array of the context for the given
5085 * namespace name associated to the given prefix
5086 *
5087 * Returns the value or NULL if not found
5088 */
5089const xmlChar *
5090xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5091 if (ctxt == NULL)
5092 return(NULL);
5093 if (prefix == NULL)
5094 return(NULL);
5095
5096#ifdef XML_XML_NAMESPACE
5097 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5098 return(XML_XML_NAMESPACE);
5099#endif
5100
Daniel Veillardc8f620b2001-04-30 20:31:33 +00005101 if (ctxt->namespaces != NULL) {
5102 int i;
5103
5104 for (i = 0;i < ctxt->nsNr;i++) {
5105 if ((ctxt->namespaces[i] != NULL) &&
5106 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5107 return(ctxt->namespaces[i]->href);
5108 }
5109 }
Owen Taylor3473f882001-02-23 17:55:21 +00005110
5111 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5112}
5113
5114/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005115 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00005116 * @ctxt: the XPath context
5117 *
5118 * Cleanup the XPath context data associated to registered variables
5119 */
5120void
5121xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5122 if (ctxt == NULL)
5123 return;
5124
Daniel Veillard42766c02002-08-22 20:52:17 +00005125 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00005126 ctxt->nsHash = NULL;
5127}
5128
5129/************************************************************************
5130 * *
5131 * Routines to handle Values *
5132 * *
5133 ************************************************************************/
5134
William M. Brack08171912003-12-29 02:52:11 +00005135/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005136
5137/**
5138 * xmlXPathNewFloat:
5139 * @val: the double value
5140 *
5141 * Create a new xmlXPathObjectPtr of type double and of value @val
5142 *
5143 * Returns the newly created object.
5144 */
5145xmlXPathObjectPtr
5146xmlXPathNewFloat(double val) {
5147 xmlXPathObjectPtr ret;
5148
5149 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5150 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005151 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005152 return(NULL);
5153 }
5154 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5155 ret->type = XPATH_NUMBER;
5156 ret->floatval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005157#ifdef XP_DEBUG_OBJ_USAGE
5158 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5159#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005160 return(ret);
5161}
5162
5163/**
5164 * xmlXPathNewBoolean:
5165 * @val: the boolean value
5166 *
5167 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5168 *
5169 * Returns the newly created object.
5170 */
5171xmlXPathObjectPtr
5172xmlXPathNewBoolean(int val) {
5173 xmlXPathObjectPtr ret;
5174
5175 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5176 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005177 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005178 return(NULL);
5179 }
5180 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5181 ret->type = XPATH_BOOLEAN;
5182 ret->boolval = (val != 0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005183#ifdef XP_DEBUG_OBJ_USAGE
5184 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5185#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005186 return(ret);
5187}
5188
5189/**
5190 * xmlXPathNewString:
5191 * @val: the xmlChar * value
5192 *
5193 * Create a new xmlXPathObjectPtr of type string and of value @val
5194 *
5195 * Returns the newly created object.
5196 */
5197xmlXPathObjectPtr
5198xmlXPathNewString(const xmlChar *val) {
5199 xmlXPathObjectPtr ret;
5200
5201 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5202 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005203 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005204 return(NULL);
5205 }
5206 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5207 ret->type = XPATH_STRING;
5208 if (val != NULL)
5209 ret->stringval = xmlStrdup(val);
5210 else
5211 ret->stringval = xmlStrdup((const xmlChar *)"");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005212#ifdef XP_DEBUG_OBJ_USAGE
5213 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5214#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005215 return(ret);
5216}
5217
5218/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005219 * xmlXPathWrapString:
5220 * @val: the xmlChar * value
5221 *
5222 * Wraps the @val string into an XPath object.
5223 *
5224 * Returns the newly created object.
5225 */
5226xmlXPathObjectPtr
5227xmlXPathWrapString (xmlChar *val) {
5228 xmlXPathObjectPtr ret;
5229
5230 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5231 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005232 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005233 return(NULL);
5234 }
5235 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5236 ret->type = XPATH_STRING;
5237 ret->stringval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005238#ifdef XP_DEBUG_OBJ_USAGE
5239 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5240#endif
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005241 return(ret);
5242}
5243
5244/**
Owen Taylor3473f882001-02-23 17:55:21 +00005245 * xmlXPathNewCString:
5246 * @val: the char * value
5247 *
5248 * Create a new xmlXPathObjectPtr of type string and of value @val
5249 *
5250 * Returns the newly created object.
5251 */
5252xmlXPathObjectPtr
5253xmlXPathNewCString(const char *val) {
5254 xmlXPathObjectPtr ret;
5255
5256 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5257 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005258 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005259 return(NULL);
5260 }
5261 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5262 ret->type = XPATH_STRING;
5263 ret->stringval = xmlStrdup(BAD_CAST val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005264#ifdef XP_DEBUG_OBJ_USAGE
5265 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5266#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005267 return(ret);
5268}
5269
5270/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005271 * xmlXPathWrapCString:
5272 * @val: the char * value
5273 *
5274 * Wraps a string into an XPath object.
5275 *
5276 * Returns the newly created object.
5277 */
5278xmlXPathObjectPtr
5279xmlXPathWrapCString (char * val) {
5280 return(xmlXPathWrapString((xmlChar *)(val)));
5281}
5282
5283/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005284 * xmlXPathWrapExternal:
5285 * @val: the user data
5286 *
5287 * Wraps the @val data into an XPath object.
5288 *
5289 * Returns the newly created object.
5290 */
5291xmlXPathObjectPtr
5292xmlXPathWrapExternal (void *val) {
5293 xmlXPathObjectPtr ret;
5294
5295 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5296 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005297 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005298 return(NULL);
5299 }
5300 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5301 ret->type = XPATH_USERS;
5302 ret->user = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005303#ifdef XP_DEBUG_OBJ_USAGE
5304 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5305#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005306 return(ret);
5307}
5308
5309/**
Owen Taylor3473f882001-02-23 17:55:21 +00005310 * xmlXPathObjectCopy:
5311 * @val: the original object
5312 *
5313 * allocate a new copy of a given object
5314 *
5315 * Returns the newly created object.
5316 */
5317xmlXPathObjectPtr
5318xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5319 xmlXPathObjectPtr ret;
5320
5321 if (val == NULL)
5322 return(NULL);
5323
5324 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5325 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005326 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005327 return(NULL);
5328 }
5329 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005330#ifdef XP_DEBUG_OBJ_USAGE
5331 xmlXPathDebugObjUsageRequested(NULL, val->type);
5332#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005333 switch (val->type) {
5334 case XPATH_BOOLEAN:
5335 case XPATH_NUMBER:
5336 case XPATH_POINT:
5337 case XPATH_RANGE:
5338 break;
5339 case XPATH_STRING:
5340 ret->stringval = xmlStrdup(val->stringval);
5341 break;
5342 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00005343#if 0
5344/*
5345 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5346 this previous handling is no longer correct, and can cause some serious
5347 problems (ref. bug 145547)
5348*/
Owen Taylor3473f882001-02-23 17:55:21 +00005349 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005350 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005351 xmlNodePtr cur, tmp;
5352 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005353
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005354 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005355 top = xmlNewDoc(NULL);
5356 top->name = (char *)
5357 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005358 ret->user = top;
5359 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005360 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005361 cur = val->nodesetval->nodeTab[0]->children;
5362 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005363 tmp = xmlDocCopyNode(cur, top, 1);
5364 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005365 cur = cur->next;
5366 }
5367 }
William M. Bracke9449c52004-07-11 14:41:20 +00005368
Daniel Veillard9adc0462003-03-24 18:39:54 +00005369 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005370 } else
Owen Taylor3473f882001-02-23 17:55:21 +00005371 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005372 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00005373 break;
William M. Bracke9449c52004-07-11 14:41:20 +00005374#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005375 case XPATH_NODESET:
5376 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005377 /* Do not deallocate the copied tree value */
5378 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005379 break;
5380 case XPATH_LOCATIONSET:
5381#ifdef LIBXML_XPTR_ENABLED
5382 {
5383 xmlLocationSetPtr loc = val->user;
5384 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5385 break;
5386 }
5387#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00005388 case XPATH_USERS:
5389 ret->user = val->user;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005390 break;
Thomas Broyer47334c02001-10-07 16:41:52 +00005391 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00005392 xmlGenericError(xmlGenericErrorContext,
5393 "xmlXPathObjectCopy: unsupported type %d\n",
5394 val->type);
5395 break;
5396 }
5397 return(ret);
5398}
5399
5400/**
5401 * xmlXPathFreeObject:
5402 * @obj: the object to free
5403 *
5404 * Free up an xmlXPathObjectPtr object.
5405 */
5406void
5407xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5408 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005409 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00005410 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00005411#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005412 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005413 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00005414 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00005415 } else
5416#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005417 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
William M. Bracke9449c52004-07-11 14:41:20 +00005418 if (obj->nodesetval != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00005419 xmlXPathFreeValueTree(obj->nodesetval);
Daniel Veillard77851712001-02-27 21:54:07 +00005420 } else {
5421 if (obj->nodesetval != NULL)
5422 xmlXPathFreeNodeSet(obj->nodesetval);
5423 }
Owen Taylor3473f882001-02-23 17:55:21 +00005424#ifdef LIBXML_XPTR_ENABLED
5425 } else if (obj->type == XPATH_LOCATIONSET) {
5426 if (obj->user != NULL)
5427 xmlXPtrFreeLocationSet(obj->user);
5428#endif
5429 } else if (obj->type == XPATH_STRING) {
5430 if (obj->stringval != NULL)
5431 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005432 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005433#ifdef XP_DEBUG_OBJ_USAGE
5434 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5435#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00005436 xmlFree(obj);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005437}
Owen Taylor3473f882001-02-23 17:55:21 +00005438
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005439/**
5440 * xmlXPathReleaseObject:
5441 * @obj: the xmlXPathObjectPtr to free or to cache
5442 *
5443 * Depending on the state of the cache this frees the given
5444 * XPath object or stores it in the cache.
5445 */
5446static void
5447xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5448{
5449#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5450 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5451 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5452
5453#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5454
5455 if (obj == NULL)
5456 return;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005457 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005458 xmlXPathFreeObject(obj);
Daniel Veillard45490ae2008-07-29 09:13:19 +00005459 } else {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005460 xmlXPathContextCachePtr cache =
5461 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005462
5463 switch (obj->type) {
5464 case XPATH_NODESET:
5465 case XPATH_XSLT_TREE:
5466 if (obj->nodesetval != NULL) {
5467 if (obj->boolval) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00005468 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005469 * It looks like the @boolval is used for
5470 * evaluation if this an XSLT Result Tree Fragment.
5471 * TODO: Check if this assumption is correct.
5472 */
5473 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5474 xmlXPathFreeValueTree(obj->nodesetval);
5475 obj->nodesetval = NULL;
5476 } else if ((obj->nodesetval->nodeMax <= 40) &&
5477 (XP_CACHE_WANTS(cache->nodesetObjs,
5478 cache->maxNodeset)))
5479 {
5480 XP_CACHE_ADD(cache->nodesetObjs, obj);
5481 goto obj_cached;
5482 } else {
5483 xmlXPathFreeNodeSet(obj->nodesetval);
5484 obj->nodesetval = NULL;
5485 }
5486 }
5487 break;
5488 case XPATH_STRING:
5489 if (obj->stringval != NULL)
5490 xmlFree(obj->stringval);
5491
5492 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5493 XP_CACHE_ADD(cache->stringObjs, obj);
5494 goto obj_cached;
5495 }
5496 break;
5497 case XPATH_BOOLEAN:
5498 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5499 XP_CACHE_ADD(cache->booleanObjs, obj);
5500 goto obj_cached;
5501 }
5502 break;
5503 case XPATH_NUMBER:
5504 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5505 XP_CACHE_ADD(cache->numberObjs, obj);
5506 goto obj_cached;
5507 }
5508 break;
5509#ifdef LIBXML_XPTR_ENABLED
5510 case XPATH_LOCATIONSET:
5511 if (obj->user != NULL) {
5512 xmlXPtrFreeLocationSet(obj->user);
5513 }
5514 goto free_obj;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005515#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005516 default:
5517 goto free_obj;
5518 }
5519
5520 /*
5521 * Fallback to adding to the misc-objects slot.
5522 */
5523 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5524 XP_CACHE_ADD(cache->miscObjs, obj);
5525 } else
5526 goto free_obj;
5527
5528obj_cached:
5529
5530#ifdef XP_DEBUG_OBJ_USAGE
5531 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5532#endif
5533
5534 if (obj->nodesetval != NULL) {
5535 xmlNodeSetPtr tmpset = obj->nodesetval;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005536
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005537 /*
5538 * TODO: Due to those nasty ns-nodes, we need to traverse
5539 * the list and free the ns-nodes.
5540 * URGENT TODO: Check if it's actually slowing things down.
5541 * Maybe we shouldn't try to preserve the list.
5542 */
5543 if (tmpset->nodeNr > 1) {
5544 int i;
5545 xmlNodePtr node;
5546
5547 for (i = 0; i < tmpset->nodeNr; i++) {
5548 node = tmpset->nodeTab[i];
5549 if ((node != NULL) &&
5550 (node->type == XML_NAMESPACE_DECL))
5551 {
5552 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5553 }
5554 }
5555 } else if (tmpset->nodeNr == 1) {
5556 if ((tmpset->nodeTab[0] != NULL) &&
5557 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5558 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
Daniel Veillard45490ae2008-07-29 09:13:19 +00005559 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005560 tmpset->nodeNr = 0;
5561 memset(obj, 0, sizeof(xmlXPathObject));
5562 obj->nodesetval = tmpset;
5563 } else
5564 memset(obj, 0, sizeof(xmlXPathObject));
5565
5566 return;
5567
5568free_obj:
5569 /*
5570 * Cache is full; free the object.
Daniel Veillard45490ae2008-07-29 09:13:19 +00005571 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005572 if (obj->nodesetval != NULL)
5573 xmlXPathFreeNodeSet(obj->nodesetval);
5574#ifdef XP_DEBUG_OBJ_USAGE
5575 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5576#endif
5577 xmlFree(obj);
5578 }
5579 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005580}
5581
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005582
5583/************************************************************************
5584 * *
5585 * Type Casting Routines *
5586 * *
5587 ************************************************************************/
5588
5589/**
5590 * xmlXPathCastBooleanToString:
5591 * @val: a boolean
5592 *
5593 * Converts a boolean to its string value.
5594 *
5595 * Returns a newly allocated string.
5596 */
5597xmlChar *
5598xmlXPathCastBooleanToString (int val) {
5599 xmlChar *ret;
5600 if (val)
5601 ret = xmlStrdup((const xmlChar *) "true");
5602 else
5603 ret = xmlStrdup((const xmlChar *) "false");
5604 return(ret);
5605}
5606
5607/**
5608 * xmlXPathCastNumberToString:
5609 * @val: a number
5610 *
5611 * Converts a number to its string value.
5612 *
5613 * Returns a newly allocated string.
5614 */
5615xmlChar *
5616xmlXPathCastNumberToString (double val) {
5617 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00005618 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005619 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005620 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005621 break;
5622 case -1:
5623 ret = xmlStrdup((const xmlChar *) "-Infinity");
5624 break;
5625 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00005626 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005627 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005628 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5629 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005630 } else {
5631 /* could be improved */
5632 char buf[100];
Daniel Veillard11ce4002006-03-10 00:36:23 +00005633 xmlXPathFormatNumber(val, buf, 99);
5634 buf[99] = 0;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005635 ret = xmlStrdup((const xmlChar *) buf);
5636 }
5637 }
5638 return(ret);
5639}
5640
5641/**
5642 * xmlXPathCastNodeToString:
5643 * @node: a node
5644 *
5645 * Converts a node to its string value.
5646 *
5647 * Returns a newly allocated string.
5648 */
5649xmlChar *
5650xmlXPathCastNodeToString (xmlNodePtr node) {
William M. Brackd611c882007-05-31 05:07:17 +00005651xmlChar *ret;
5652 if ((ret = xmlNodeGetContent(node)) == NULL)
5653 ret = xmlStrdup((const xmlChar *) "");
5654 return(ret);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005655}
5656
5657/**
5658 * xmlXPathCastNodeSetToString:
5659 * @ns: a node-set
5660 *
5661 * Converts a node-set to its string value.
5662 *
5663 * Returns a newly allocated string.
5664 */
5665xmlChar *
5666xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5667 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5668 return(xmlStrdup((const xmlChar *) ""));
5669
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00005670 if (ns->nodeNr > 1)
5671 xmlXPathNodeSetSort(ns);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005672 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5673}
5674
5675/**
5676 * xmlXPathCastToString:
5677 * @val: an XPath object
5678 *
5679 * Converts an existing object to its string() equivalent
5680 *
Kasimier T. Buchcik50128ad2006-08-15 13:04:07 +00005681 * Returns the allocated string value of the object, NULL in case of error.
Daniel Veillard45490ae2008-07-29 09:13:19 +00005682 * It's up to the caller to free the string memory with xmlFree().
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005683 */
5684xmlChar *
5685xmlXPathCastToString(xmlXPathObjectPtr val) {
5686 xmlChar *ret = NULL;
5687
5688 if (val == NULL)
5689 return(xmlStrdup((const xmlChar *) ""));
5690 switch (val->type) {
5691 case XPATH_UNDEFINED:
5692#ifdef DEBUG_EXPR
5693 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5694#endif
5695 ret = xmlStrdup((const xmlChar *) "");
5696 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005697 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005698 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005699 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5700 break;
5701 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00005702 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005703 case XPATH_BOOLEAN:
5704 ret = xmlXPathCastBooleanToString(val->boolval);
5705 break;
5706 case XPATH_NUMBER: {
5707 ret = xmlXPathCastNumberToString(val->floatval);
5708 break;
5709 }
5710 case XPATH_USERS:
5711 case XPATH_POINT:
5712 case XPATH_RANGE:
5713 case XPATH_LOCATIONSET:
5714 TODO
5715 ret = xmlStrdup((const xmlChar *) "");
5716 break;
5717 }
5718 return(ret);
5719}
5720
5721/**
5722 * xmlXPathConvertString:
5723 * @val: an XPath object
5724 *
5725 * Converts an existing object to its string() equivalent
5726 *
5727 * Returns the new object, the old one is freed (or the operation
5728 * is done directly on @val)
5729 */
5730xmlXPathObjectPtr
5731xmlXPathConvertString(xmlXPathObjectPtr val) {
5732 xmlChar *res = NULL;
5733
5734 if (val == NULL)
5735 return(xmlXPathNewCString(""));
5736
5737 switch (val->type) {
5738 case XPATH_UNDEFINED:
5739#ifdef DEBUG_EXPR
5740 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5741#endif
5742 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005743 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005744 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005745 res = xmlXPathCastNodeSetToString(val->nodesetval);
5746 break;
5747 case XPATH_STRING:
5748 return(val);
5749 case XPATH_BOOLEAN:
5750 res = xmlXPathCastBooleanToString(val->boolval);
5751 break;
5752 case XPATH_NUMBER:
5753 res = xmlXPathCastNumberToString(val->floatval);
5754 break;
5755 case XPATH_USERS:
5756 case XPATH_POINT:
5757 case XPATH_RANGE:
5758 case XPATH_LOCATIONSET:
5759 TODO;
5760 break;
5761 }
5762 xmlXPathFreeObject(val);
5763 if (res == NULL)
5764 return(xmlXPathNewCString(""));
5765 return(xmlXPathWrapString(res));
5766}
5767
5768/**
5769 * xmlXPathCastBooleanToNumber:
5770 * @val: a boolean
5771 *
5772 * Converts a boolean to its number value
5773 *
5774 * Returns the number value
5775 */
5776double
5777xmlXPathCastBooleanToNumber(int val) {
5778 if (val)
5779 return(1.0);
5780 return(0.0);
5781}
5782
5783/**
5784 * xmlXPathCastStringToNumber:
5785 * @val: a string
5786 *
5787 * Converts a string to its number value
5788 *
5789 * Returns the number value
5790 */
5791double
5792xmlXPathCastStringToNumber(const xmlChar * val) {
5793 return(xmlXPathStringEvalNumber(val));
5794}
5795
5796/**
5797 * xmlXPathCastNodeToNumber:
5798 * @node: a node
5799 *
5800 * Converts a node to its number value
5801 *
5802 * Returns the number value
5803 */
5804double
5805xmlXPathCastNodeToNumber (xmlNodePtr node) {
5806 xmlChar *strval;
5807 double ret;
5808
5809 if (node == NULL)
5810 return(xmlXPathNAN);
5811 strval = xmlXPathCastNodeToString(node);
5812 if (strval == NULL)
5813 return(xmlXPathNAN);
5814 ret = xmlXPathCastStringToNumber(strval);
5815 xmlFree(strval);
5816
5817 return(ret);
5818}
5819
5820/**
5821 * xmlXPathCastNodeSetToNumber:
5822 * @ns: a node-set
5823 *
5824 * Converts a node-set to its number value
5825 *
5826 * Returns the number value
5827 */
5828double
5829xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5830 xmlChar *str;
5831 double ret;
5832
5833 if (ns == NULL)
5834 return(xmlXPathNAN);
5835 str = xmlXPathCastNodeSetToString(ns);
5836 ret = xmlXPathCastStringToNumber(str);
5837 xmlFree(str);
5838 return(ret);
5839}
5840
5841/**
5842 * xmlXPathCastToNumber:
5843 * @val: an XPath object
5844 *
5845 * Converts an XPath object to its number value
5846 *
5847 * Returns the number value
5848 */
5849double
5850xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5851 double ret = 0.0;
5852
5853 if (val == NULL)
5854 return(xmlXPathNAN);
5855 switch (val->type) {
5856 case XPATH_UNDEFINED:
5857#ifdef DEGUB_EXPR
5858 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5859#endif
5860 ret = xmlXPathNAN;
5861 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005862 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005863 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005864 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5865 break;
5866 case XPATH_STRING:
5867 ret = xmlXPathCastStringToNumber(val->stringval);
5868 break;
5869 case XPATH_NUMBER:
5870 ret = val->floatval;
5871 break;
5872 case XPATH_BOOLEAN:
5873 ret = xmlXPathCastBooleanToNumber(val->boolval);
5874 break;
5875 case XPATH_USERS:
5876 case XPATH_POINT:
5877 case XPATH_RANGE:
5878 case XPATH_LOCATIONSET:
5879 TODO;
5880 ret = xmlXPathNAN;
5881 break;
5882 }
5883 return(ret);
5884}
5885
5886/**
5887 * xmlXPathConvertNumber:
5888 * @val: an XPath object
5889 *
5890 * Converts an existing object to its number() equivalent
5891 *
5892 * Returns the new object, the old one is freed (or the operation
5893 * is done directly on @val)
5894 */
5895xmlXPathObjectPtr
5896xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5897 xmlXPathObjectPtr ret;
5898
5899 if (val == NULL)
5900 return(xmlXPathNewFloat(0.0));
5901 if (val->type == XPATH_NUMBER)
5902 return(val);
5903 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5904 xmlXPathFreeObject(val);
5905 return(ret);
5906}
5907
5908/**
5909 * xmlXPathCastNumberToBoolean:
5910 * @val: a number
5911 *
5912 * Converts a number to its boolean value
5913 *
5914 * Returns the boolean value
5915 */
5916int
5917xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00005918 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005919 return(0);
5920 return(1);
5921}
5922
5923/**
5924 * xmlXPathCastStringToBoolean:
5925 * @val: a string
5926 *
5927 * Converts a string to its boolean value
5928 *
5929 * Returns the boolean value
5930 */
5931int
5932xmlXPathCastStringToBoolean (const xmlChar *val) {
5933 if ((val == NULL) || (xmlStrlen(val) == 0))
5934 return(0);
5935 return(1);
5936}
5937
5938/**
5939 * xmlXPathCastNodeSetToBoolean:
5940 * @ns: a node-set
5941 *
5942 * Converts a node-set to its boolean value
5943 *
5944 * Returns the boolean value
5945 */
5946int
5947xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5948 if ((ns == NULL) || (ns->nodeNr == 0))
5949 return(0);
5950 return(1);
5951}
5952
5953/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005954 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005955 * @val: an XPath object
5956 *
5957 * Converts an XPath object to its boolean value
5958 *
5959 * Returns the boolean value
5960 */
5961int
5962xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5963 int ret = 0;
5964
5965 if (val == NULL)
5966 return(0);
5967 switch (val->type) {
5968 case XPATH_UNDEFINED:
5969#ifdef DEBUG_EXPR
5970 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
5971#endif
5972 ret = 0;
5973 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005974 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005975 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005976 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5977 break;
5978 case XPATH_STRING:
5979 ret = xmlXPathCastStringToBoolean(val->stringval);
5980 break;
5981 case XPATH_NUMBER:
5982 ret = xmlXPathCastNumberToBoolean(val->floatval);
5983 break;
5984 case XPATH_BOOLEAN:
5985 ret = val->boolval;
5986 break;
5987 case XPATH_USERS:
5988 case XPATH_POINT:
5989 case XPATH_RANGE:
5990 case XPATH_LOCATIONSET:
5991 TODO;
5992 ret = 0;
5993 break;
5994 }
5995 return(ret);
5996}
5997
5998
5999/**
6000 * xmlXPathConvertBoolean:
6001 * @val: an XPath object
6002 *
6003 * Converts an existing object to its boolean() equivalent
6004 *
6005 * Returns the new object, the old one is freed (or the operation
6006 * is done directly on @val)
6007 */
6008xmlXPathObjectPtr
6009xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6010 xmlXPathObjectPtr ret;
6011
6012 if (val == NULL)
6013 return(xmlXPathNewBoolean(0));
6014 if (val->type == XPATH_BOOLEAN)
6015 return(val);
6016 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6017 xmlXPathFreeObject(val);
6018 return(ret);
6019}
6020
Owen Taylor3473f882001-02-23 17:55:21 +00006021/************************************************************************
6022 * *
6023 * Routines to handle XPath contexts *
6024 * *
6025 ************************************************************************/
6026
6027/**
6028 * xmlXPathNewContext:
6029 * @doc: the XML document
6030 *
6031 * Create a new xmlXPathContext
6032 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00006033 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00006034 */
6035xmlXPathContextPtr
6036xmlXPathNewContext(xmlDocPtr doc) {
6037 xmlXPathContextPtr ret;
6038
6039 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6040 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006041 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006042 return(NULL);
6043 }
6044 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6045 ret->doc = doc;
6046 ret->node = NULL;
6047
6048 ret->varHash = NULL;
6049
6050 ret->nb_types = 0;
6051 ret->max_types = 0;
6052 ret->types = NULL;
6053
6054 ret->funcHash = xmlHashCreate(0);
6055
6056 ret->nb_axis = 0;
6057 ret->max_axis = 0;
6058 ret->axis = NULL;
6059
6060 ret->nsHash = NULL;
6061 ret->user = NULL;
6062
6063 ret->contextSize = -1;
6064 ret->proximityPosition = -1;
6065
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006066#ifdef XP_DEFAULT_CACHE_ON
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006067 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006068 xmlXPathFreeContext(ret);
6069 return(NULL);
6070 }
6071#endif
6072
Daniel Veillard45490ae2008-07-29 09:13:19 +00006073 xmlXPathRegisterAllFunctions(ret);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006074
Owen Taylor3473f882001-02-23 17:55:21 +00006075 return(ret);
6076}
6077
6078/**
6079 * xmlXPathFreeContext:
6080 * @ctxt: the context to free
6081 *
6082 * Free up an xmlXPathContext
6083 */
6084void
6085xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006086 if (ctxt == NULL) return;
6087
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006088 if (ctxt->cache != NULL)
6089 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
Owen Taylor3473f882001-02-23 17:55:21 +00006090 xmlXPathRegisteredNsCleanup(ctxt);
6091 xmlXPathRegisteredFuncsCleanup(ctxt);
6092 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006093 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00006094 xmlFree(ctxt);
6095}
6096
6097/************************************************************************
6098 * *
6099 * Routines to handle XPath parser contexts *
6100 * *
6101 ************************************************************************/
6102
6103#define CHECK_CTXT(ctxt) \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006104 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00006105 __xmlRaiseError(NULL, NULL, NULL, \
6106 NULL, NULL, XML_FROM_XPATH, \
6107 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6108 __FILE__, __LINE__, \
6109 NULL, NULL, NULL, 0, 0, \
6110 "NULL context pointer\n"); \
6111 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00006112 } \
6113
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006114#define CHECK_CTXT_NEG(ctxt) \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006115 if (ctxt == NULL) { \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006116 __xmlRaiseError(NULL, NULL, NULL, \
6117 NULL, NULL, XML_FROM_XPATH, \
6118 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6119 __FILE__, __LINE__, \
6120 NULL, NULL, NULL, 0, 0, \
6121 "NULL context pointer\n"); \
6122 return(-1); \
6123 } \
6124
Owen Taylor3473f882001-02-23 17:55:21 +00006125
6126#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00006127 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006128 (ctxt->doc->children == NULL)) { \
Daniel Veillard57b25162004-11-06 14:50:18 +00006129 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00006130 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00006131 }
Owen Taylor3473f882001-02-23 17:55:21 +00006132
6133
6134/**
6135 * xmlXPathNewParserContext:
6136 * @str: the XPath expression
6137 * @ctxt: the XPath context
6138 *
6139 * Create a new xmlXPathParserContext
6140 *
6141 * Returns the xmlXPathParserContext just allocated.
6142 */
6143xmlXPathParserContextPtr
6144xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6145 xmlXPathParserContextPtr ret;
6146
6147 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6148 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006149 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006150 return(NULL);
6151 }
6152 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6153 ret->cur = ret->base = str;
6154 ret->context = ctxt;
6155
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006156 ret->comp = xmlXPathNewCompExpr();
6157 if (ret->comp == NULL) {
6158 xmlFree(ret->valueTab);
6159 xmlFree(ret);
6160 return(NULL);
6161 }
Daniel Veillard4773df22004-01-23 13:15:13 +00006162 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6163 ret->comp->dict = ctxt->dict;
6164 xmlDictReference(ret->comp->dict);
6165 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006166
6167 return(ret);
6168}
6169
6170/**
6171 * xmlXPathCompParserContext:
6172 * @comp: the XPath compiled expression
6173 * @ctxt: the XPath context
6174 *
6175 * Create a new xmlXPathParserContext when processing a compiled expression
6176 *
6177 * Returns the xmlXPathParserContext just allocated.
6178 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006179static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006180xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6181 xmlXPathParserContextPtr ret;
6182
6183 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6184 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006185 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006186 return(NULL);
6187 }
6188 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6189
Owen Taylor3473f882001-02-23 17:55:21 +00006190 /* Allocate the value stack */
Daniel Veillard45490ae2008-07-29 09:13:19 +00006191 ret->valueTab = (xmlXPathObjectPtr *)
Owen Taylor3473f882001-02-23 17:55:21 +00006192 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006193 if (ret->valueTab == NULL) {
6194 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006195 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006196 return(NULL);
6197 }
Owen Taylor3473f882001-02-23 17:55:21 +00006198 ret->valueNr = 0;
6199 ret->valueMax = 10;
6200 ret->value = NULL;
Daniel Veillardf5048b32011-08-18 17:10:13 +08006201 ret->valueFrame = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006202
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006203 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006204 ret->comp = comp;
6205
Owen Taylor3473f882001-02-23 17:55:21 +00006206 return(ret);
6207}
6208
6209/**
6210 * xmlXPathFreeParserContext:
6211 * @ctxt: the context to free
6212 *
6213 * Free up an xmlXPathParserContext
6214 */
6215void
6216xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6217 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006218 xmlFree(ctxt->valueTab);
6219 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00006220 if (ctxt->comp != NULL) {
6221#ifdef XPATH_STREAMING
6222 if (ctxt->comp->stream != NULL) {
6223 xmlFreePatternList(ctxt->comp->stream);
6224 ctxt->comp->stream = NULL;
6225 }
6226#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006227 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard56de87e2005-02-16 00:22:29 +00006228 }
Owen Taylor3473f882001-02-23 17:55:21 +00006229 xmlFree(ctxt);
6230}
6231
6232/************************************************************************
6233 * *
6234 * The implicit core function library *
6235 * *
6236 ************************************************************************/
6237
Owen Taylor3473f882001-02-23 17:55:21 +00006238/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006239 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00006240 * @node: a node pointer
6241 *
6242 * Function computing the beginning of the string value of the node,
6243 * used to speed up comparisons
6244 *
6245 * Returns an int usable as a hash
6246 */
6247static unsigned int
6248xmlXPathNodeValHash(xmlNodePtr node) {
6249 int len = 2;
6250 const xmlChar * string = NULL;
6251 xmlNodePtr tmp = NULL;
6252 unsigned int ret = 0;
6253
6254 if (node == NULL)
6255 return(0);
6256
Daniel Veillard9adc0462003-03-24 18:39:54 +00006257 if (node->type == XML_DOCUMENT_NODE) {
6258 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6259 if (tmp == NULL)
6260 node = node->children;
6261 else
6262 node = tmp;
6263
6264 if (node == NULL)
6265 return(0);
6266 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006267
6268 switch (node->type) {
6269 case XML_COMMENT_NODE:
6270 case XML_PI_NODE:
6271 case XML_CDATA_SECTION_NODE:
6272 case XML_TEXT_NODE:
6273 string = node->content;
6274 if (string == NULL)
6275 return(0);
6276 if (string[0] == 0)
6277 return(0);
6278 return(((unsigned int) string[0]) +
6279 (((unsigned int) string[1]) << 8));
6280 case XML_NAMESPACE_DECL:
6281 string = ((xmlNsPtr)node)->href;
6282 if (string == NULL)
6283 return(0);
6284 if (string[0] == 0)
6285 return(0);
6286 return(((unsigned int) string[0]) +
6287 (((unsigned int) string[1]) << 8));
6288 case XML_ATTRIBUTE_NODE:
6289 tmp = ((xmlAttrPtr) node)->children;
6290 break;
6291 case XML_ELEMENT_NODE:
6292 tmp = node->children;
6293 break;
6294 default:
6295 return(0);
6296 }
6297 while (tmp != NULL) {
6298 switch (tmp->type) {
6299 case XML_COMMENT_NODE:
6300 case XML_PI_NODE:
6301 case XML_CDATA_SECTION_NODE:
6302 case XML_TEXT_NODE:
6303 string = tmp->content;
6304 break;
6305 case XML_NAMESPACE_DECL:
6306 string = ((xmlNsPtr)tmp)->href;
6307 break;
6308 default:
6309 break;
6310 }
6311 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006312 if (len == 1) {
6313 return(ret + (((unsigned int) string[0]) << 8));
6314 }
6315 if (string[1] == 0) {
6316 len = 1;
6317 ret = (unsigned int) string[0];
6318 } else {
6319 return(((unsigned int) string[0]) +
6320 (((unsigned int) string[1]) << 8));
6321 }
6322 }
6323 /*
6324 * Skip to next node
6325 */
6326 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6327 if (tmp->children->type != XML_ENTITY_DECL) {
6328 tmp = tmp->children;
6329 continue;
6330 }
6331 }
6332 if (tmp == node)
6333 break;
6334
6335 if (tmp->next != NULL) {
6336 tmp = tmp->next;
6337 continue;
6338 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00006339
Daniel Veillardf06307e2001-07-03 10:35:50 +00006340 do {
6341 tmp = tmp->parent;
6342 if (tmp == NULL)
6343 break;
6344 if (tmp == node) {
6345 tmp = NULL;
6346 break;
6347 }
6348 if (tmp->next != NULL) {
6349 tmp = tmp->next;
6350 break;
6351 }
6352 } while (tmp != NULL);
6353 }
6354 return(ret);
6355}
6356
6357/**
6358 * xmlXPathStringHash:
6359 * @string: a string
6360 *
6361 * Function computing the beginning of the string value of the node,
6362 * used to speed up comparisons
6363 *
6364 * Returns an int usable as a hash
6365 */
6366static unsigned int
6367xmlXPathStringHash(const xmlChar * string) {
6368 if (string == NULL)
6369 return((unsigned int) 0);
6370 if (string[0] == 0)
6371 return(0);
6372 return(((unsigned int) string[0]) +
6373 (((unsigned int) string[1]) << 8));
6374}
6375
6376/**
Owen Taylor3473f882001-02-23 17:55:21 +00006377 * xmlXPathCompareNodeSetFloat:
6378 * @ctxt: the XPath Parser context
6379 * @inf: less than (1) or greater than (0)
6380 * @strict: is the comparison strict
6381 * @arg: the node set
6382 * @f: the value
6383 *
6384 * Implement the compare operation between a nodeset and a number
6385 * @ns < @val (1, 1, ...
6386 * @ns <= @val (1, 0, ...
6387 * @ns > @val (0, 1, ...
6388 * @ns >= @val (0, 0, ...
6389 *
6390 * If one object to be compared is a node-set and the other is a number,
6391 * then the comparison will be true if and only if there is a node in the
6392 * node-set such that the result of performing the comparison on the number
6393 * to be compared and on the result of converting the string-value of that
6394 * node to a number using the number function is true.
6395 *
6396 * Returns 0 or 1 depending on the results of the test.
6397 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006398static int
Owen Taylor3473f882001-02-23 17:55:21 +00006399xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6400 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6401 int i, ret = 0;
6402 xmlNodeSetPtr ns;
6403 xmlChar *str2;
6404
6405 if ((f == NULL) || (arg == NULL) ||
6406 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006407 xmlXPathReleaseObject(ctxt->context, arg);
6408 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006409 return(0);
6410 }
6411 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006412 if (ns != NULL) {
6413 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006414 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006415 if (str2 != NULL) {
6416 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006417 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006418 xmlFree(str2);
6419 xmlXPathNumberFunction(ctxt, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006420 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006421 ret = xmlXPathCompareValues(ctxt, inf, strict);
6422 if (ret)
6423 break;
6424 }
6425 }
Owen Taylor3473f882001-02-23 17:55:21 +00006426 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006427 xmlXPathReleaseObject(ctxt->context, arg);
6428 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006429 return(ret);
6430}
6431
6432/**
6433 * xmlXPathCompareNodeSetString:
6434 * @ctxt: the XPath Parser context
6435 * @inf: less than (1) or greater than (0)
6436 * @strict: is the comparison strict
6437 * @arg: the node set
6438 * @s: the value
6439 *
6440 * Implement the compare operation between a nodeset and a string
6441 * @ns < @val (1, 1, ...
6442 * @ns <= @val (1, 0, ...
6443 * @ns > @val (0, 1, ...
6444 * @ns >= @val (0, 0, ...
6445 *
6446 * If one object to be compared is a node-set and the other is a string,
6447 * then the comparison will be true if and only if there is a node in
6448 * the node-set such that the result of performing the comparison on the
6449 * string-value of the node and the other string is true.
6450 *
6451 * Returns 0 or 1 depending on the results of the test.
6452 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006453static int
Owen Taylor3473f882001-02-23 17:55:21 +00006454xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6455 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6456 int i, ret = 0;
6457 xmlNodeSetPtr ns;
6458 xmlChar *str2;
6459
6460 if ((s == NULL) || (arg == NULL) ||
6461 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006462 xmlXPathReleaseObject(ctxt->context, arg);
6463 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006464 return(0);
6465 }
6466 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006467 if (ns != NULL) {
6468 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006469 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006470 if (str2 != NULL) {
6471 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006472 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006473 xmlFree(str2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006474 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006475 ret = xmlXPathCompareValues(ctxt, inf, strict);
6476 if (ret)
6477 break;
6478 }
6479 }
Owen Taylor3473f882001-02-23 17:55:21 +00006480 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006481 xmlXPathReleaseObject(ctxt->context, arg);
6482 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006483 return(ret);
6484}
6485
6486/**
6487 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006488 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00006489 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006490 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00006491 * @arg2: the second node set object
6492 *
6493 * Implement the compare operation on nodesets:
6494 *
6495 * If both objects to be compared are node-sets, then the comparison
6496 * will be true if and only if there is a node in the first node-set
6497 * and a node in the second node-set such that the result of performing
Daniel Veillard45490ae2008-07-29 09:13:19 +00006498 * the comparison on the string-values of the two nodes is true.
Owen Taylor3473f882001-02-23 17:55:21 +00006499 * ....
6500 * When neither object to be compared is a node-set and the operator
6501 * is <=, <, >= or >, then the objects are compared by converting both
6502 * objects to numbers and comparing the numbers according to IEEE 754.
6503 * ....
6504 * The number function converts its argument to a number as follows:
6505 * - a string that consists of optional whitespace followed by an
6506 * optional minus sign followed by a Number followed by whitespace
6507 * is converted to the IEEE 754 number that is nearest (according
6508 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6509 * represented by the string; any other string is converted to NaN
6510 *
6511 * Conclusion all nodes need to be converted first to their string value
Daniel Veillard45490ae2008-07-29 09:13:19 +00006512 * and then the comparison must be done when possible
Owen Taylor3473f882001-02-23 17:55:21 +00006513 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006514static int
6515xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00006516 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6517 int i, j, init = 0;
6518 double val1;
6519 double *values2;
6520 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006521 xmlNodeSetPtr ns1;
6522 xmlNodeSetPtr ns2;
6523
6524 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006525 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6526 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006527 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006528 }
Owen Taylor3473f882001-02-23 17:55:21 +00006529 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006530 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6531 xmlXPathFreeObject(arg1);
6532 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006533 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006534 }
Owen Taylor3473f882001-02-23 17:55:21 +00006535
6536 ns1 = arg1->nodesetval;
6537 ns2 = arg2->nodesetval;
6538
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006539 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006540 xmlXPathFreeObject(arg1);
6541 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006542 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006543 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006544 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006545 xmlXPathFreeObject(arg1);
6546 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006547 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006548 }
Owen Taylor3473f882001-02-23 17:55:21 +00006549
6550 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6551 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006552 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00006553 xmlXPathFreeObject(arg1);
6554 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006555 return(0);
6556 }
6557 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006558 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00006559 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00006560 continue;
6561 for (j = 0;j < ns2->nodeNr;j++) {
6562 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006563 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00006564 }
Daniel Veillardcda96922001-08-21 10:56:31 +00006565 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00006566 continue;
Daniel Veillard45490ae2008-07-29 09:13:19 +00006567 if (inf && strict)
Owen Taylor3473f882001-02-23 17:55:21 +00006568 ret = (val1 < values2[j]);
6569 else if (inf && !strict)
6570 ret = (val1 <= values2[j]);
6571 else if (!inf && strict)
6572 ret = (val1 > values2[j]);
6573 else if (!inf && !strict)
6574 ret = (val1 >= values2[j]);
6575 if (ret)
6576 break;
6577 }
6578 if (ret)
6579 break;
6580 init = 1;
6581 }
6582 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006583 xmlXPathFreeObject(arg1);
6584 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006585 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006586}
6587
6588/**
6589 * xmlXPathCompareNodeSetValue:
6590 * @ctxt: the XPath Parser context
6591 * @inf: less than (1) or greater than (0)
6592 * @strict: is the comparison strict
6593 * @arg: the node set
6594 * @val: the value
6595 *
6596 * Implement the compare operation between a nodeset and a value
6597 * @ns < @val (1, 1, ...
6598 * @ns <= @val (1, 0, ...
6599 * @ns > @val (0, 1, ...
6600 * @ns >= @val (0, 0, ...
6601 *
6602 * If one object to be compared is a node-set and the other is a boolean,
6603 * then the comparison will be true if and only if the result of performing
6604 * the comparison on the boolean and on the result of converting
6605 * the node-set to a boolean using the boolean function is true.
6606 *
6607 * Returns 0 or 1 depending on the results of the test.
6608 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006609static int
Owen Taylor3473f882001-02-23 17:55:21 +00006610xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6611 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6612 if ((val == NULL) || (arg == NULL) ||
6613 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6614 return(0);
6615
6616 switch(val->type) {
6617 case XPATH_NUMBER:
6618 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6619 case XPATH_NODESET:
6620 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006621 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00006622 case XPATH_STRING:
6623 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6624 case XPATH_BOOLEAN:
6625 valuePush(ctxt, arg);
6626 xmlXPathBooleanFunction(ctxt, 1);
6627 valuePush(ctxt, val);
6628 return(xmlXPathCompareValues(ctxt, inf, strict));
6629 default:
6630 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00006631 }
6632 return(0);
6633}
6634
6635/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006636 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00006637 * @arg: the nodeset object argument
6638 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00006639 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006640 *
6641 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6642 * If one object to be compared is a node-set and the other is a string,
6643 * then the comparison will be true if and only if there is a node in
6644 * the node-set such that the result of performing the comparison on the
6645 * string-value of the node and the other string is true.
6646 *
6647 * Returns 0 or 1 depending on the results of the test.
6648 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006649static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006650xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006651{
Owen Taylor3473f882001-02-23 17:55:21 +00006652 int i;
6653 xmlNodeSetPtr ns;
6654 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006655 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00006656
6657 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00006658 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6659 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006660 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00006661 /*
6662 * A NULL nodeset compared with a string is always false
6663 * (since there is no node equal, and no node not equal)
6664 */
6665 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00006666 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00006667 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006668 for (i = 0; i < ns->nodeNr; i++) {
6669 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6670 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6671 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6672 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006673 if (neq)
6674 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006675 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00006676 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6677 if (neq)
6678 continue;
6679 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006680 } else if (neq) {
6681 if (str2 != NULL)
6682 xmlFree(str2);
6683 return (1);
6684 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006685 if (str2 != NULL)
6686 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006687 } else if (neq)
6688 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00006689 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006690 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006691}
6692
6693/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006694 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00006695 * @arg: the nodeset object argument
6696 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00006697 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006698 *
6699 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6700 * If one object to be compared is a node-set and the other is a number,
6701 * then the comparison will be true if and only if there is a node in
6702 * the node-set such that the result of performing the comparison on the
6703 * number to be compared and on the result of converting the string-value
6704 * of that node to a number using the number function is true.
6705 *
6706 * Returns 0 or 1 depending on the results of the test.
6707 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006708static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006709xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6710 xmlXPathObjectPtr arg, double f, int neq) {
6711 int i, ret=0;
6712 xmlNodeSetPtr ns;
6713 xmlChar *str2;
6714 xmlXPathObjectPtr val;
6715 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00006716
6717 if ((arg == NULL) ||
6718 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6719 return(0);
6720
William M. Brack0c022ad2002-07-12 00:56:01 +00006721 ns = arg->nodesetval;
6722 if (ns != NULL) {
6723 for (i=0;i<ns->nodeNr;i++) {
6724 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6725 if (str2 != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006726 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
William M. Brack0c022ad2002-07-12 00:56:01 +00006727 xmlFree(str2);
6728 xmlXPathNumberFunction(ctxt, 1);
6729 val = valuePop(ctxt);
6730 v = val->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006731 xmlXPathReleaseObject(ctxt->context, val);
William M. Brack0c022ad2002-07-12 00:56:01 +00006732 if (!xmlXPathIsNaN(v)) {
6733 if ((!neq) && (v==f)) {
6734 ret = 1;
6735 break;
6736 } else if ((neq) && (v!=f)) {
6737 ret = 1;
6738 break;
6739 }
William M. Brack32f0f712005-07-14 07:00:33 +00006740 } else { /* NaN is unequal to any value */
6741 if (neq)
6742 ret = 1;
William M. Brack0c022ad2002-07-12 00:56:01 +00006743 }
6744 }
6745 }
6746 }
6747
6748 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006749}
6750
6751
6752/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006753 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00006754 * @arg1: first nodeset object argument
6755 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00006756 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006757 *
William M. Brack0c022ad2002-07-12 00:56:01 +00006758 * Implement the equal / not equal operation on XPath nodesets:
6759 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00006760 * If both objects to be compared are node-sets, then the comparison
6761 * will be true if and only if there is a node in the first node-set and
6762 * a node in the second node-set such that the result of performing the
6763 * comparison on the string-values of the two nodes is true.
6764 *
6765 * (needless to say, this is a costly operation)
6766 *
6767 * Returns 0 or 1 depending on the results of the test.
6768 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006769static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006770xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00006771 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006772 unsigned int *hashs1;
6773 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00006774 xmlChar **values1;
6775 xmlChar **values2;
6776 int ret = 0;
6777 xmlNodeSetPtr ns1;
6778 xmlNodeSetPtr ns2;
6779
6780 if ((arg1 == NULL) ||
6781 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6782 return(0);
6783 if ((arg2 == NULL) ||
6784 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6785 return(0);
6786
6787 ns1 = arg1->nodesetval;
6788 ns2 = arg2->nodesetval;
6789
Daniel Veillard911f49a2001-04-07 15:39:35 +00006790 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006791 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006792 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006793 return(0);
6794
6795 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00006796 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00006797 */
William M. Brack0c022ad2002-07-12 00:56:01 +00006798 if (neq == 0)
6799 for (i = 0;i < ns1->nodeNr;i++)
6800 for (j = 0;j < ns2->nodeNr;j++)
6801 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6802 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006803
6804 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006805 if (values1 == NULL) {
6806 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006807 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006808 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006809 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6810 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006811 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006812 xmlFree(values1);
6813 return(0);
6814 }
Owen Taylor3473f882001-02-23 17:55:21 +00006815 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6816 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6817 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006818 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006819 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00006820 xmlFree(values1);
6821 return(0);
6822 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006823 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6824 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006825 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006826 xmlFree(hashs1);
6827 xmlFree(values1);
6828 xmlFree(values2);
6829 return(0);
6830 }
Owen Taylor3473f882001-02-23 17:55:21 +00006831 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6832 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006833 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006834 for (j = 0;j < ns2->nodeNr;j++) {
6835 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006836 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006837 if (hashs1[i] != hashs2[j]) {
6838 if (neq) {
6839 ret = 1;
6840 break;
6841 }
6842 }
6843 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006844 if (values1[i] == NULL)
6845 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6846 if (values2[j] == NULL)
6847 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006848 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006849 if (ret)
6850 break;
6851 }
Owen Taylor3473f882001-02-23 17:55:21 +00006852 }
6853 if (ret)
6854 break;
6855 }
6856 for (i = 0;i < ns1->nodeNr;i++)
6857 if (values1[i] != NULL)
6858 xmlFree(values1[i]);
6859 for (j = 0;j < ns2->nodeNr;j++)
6860 if (values2[j] != NULL)
6861 xmlFree(values2[j]);
6862 xmlFree(values1);
6863 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006864 xmlFree(hashs1);
6865 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00006866 return(ret);
6867}
6868
William M. Brack0c022ad2002-07-12 00:56:01 +00006869static int
6870xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6871 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00006872 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00006873 /*
6874 *At this point we are assured neither arg1 nor arg2
6875 *is a nodeset, so we can just pick the appropriate routine.
6876 */
Owen Taylor3473f882001-02-23 17:55:21 +00006877 switch (arg1->type) {
6878 case XPATH_UNDEFINED:
6879#ifdef DEBUG_EXPR
6880 xmlGenericError(xmlGenericErrorContext,
6881 "Equal: undefined\n");
6882#endif
6883 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006884 case XPATH_BOOLEAN:
6885 switch (arg2->type) {
6886 case XPATH_UNDEFINED:
6887#ifdef DEBUG_EXPR
6888 xmlGenericError(xmlGenericErrorContext,
6889 "Equal: undefined\n");
6890#endif
6891 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006892 case XPATH_BOOLEAN:
6893#ifdef DEBUG_EXPR
6894 xmlGenericError(xmlGenericErrorContext,
6895 "Equal: %d boolean %d \n",
6896 arg1->boolval, arg2->boolval);
6897#endif
6898 ret = (arg1->boolval == arg2->boolval);
6899 break;
6900 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00006901 ret = (arg1->boolval ==
6902 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006903 break;
6904 case XPATH_STRING:
6905 if ((arg2->stringval == NULL) ||
6906 (arg2->stringval[0] == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00006907 else
Owen Taylor3473f882001-02-23 17:55:21 +00006908 ret = 1;
6909 ret = (arg1->boolval == ret);
6910 break;
6911 case XPATH_USERS:
6912 case XPATH_POINT:
6913 case XPATH_RANGE:
6914 case XPATH_LOCATIONSET:
6915 TODO
6916 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006917 case XPATH_NODESET:
6918 case XPATH_XSLT_TREE:
6919 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006920 }
6921 break;
6922 case XPATH_NUMBER:
6923 switch (arg2->type) {
6924 case XPATH_UNDEFINED:
6925#ifdef DEBUG_EXPR
6926 xmlGenericError(xmlGenericErrorContext,
6927 "Equal: undefined\n");
6928#endif
6929 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006930 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00006931 ret = (arg2->boolval==
6932 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006933 break;
6934 case XPATH_STRING:
6935 valuePush(ctxt, arg2);
6936 xmlXPathNumberFunction(ctxt, 1);
6937 arg2 = valuePop(ctxt);
6938 /* no break on purpose */
6939 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006940 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00006941 if (xmlXPathIsNaN(arg1->floatval) ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00006942 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00006943 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006944 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6945 if (xmlXPathIsInf(arg2->floatval) == 1)
6946 ret = 1;
6947 else
6948 ret = 0;
6949 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6950 if (xmlXPathIsInf(arg2->floatval) == -1)
6951 ret = 1;
6952 else
6953 ret = 0;
6954 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6955 if (xmlXPathIsInf(arg1->floatval) == 1)
6956 ret = 1;
6957 else
6958 ret = 0;
6959 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6960 if (xmlXPathIsInf(arg1->floatval) == -1)
6961 ret = 1;
6962 else
6963 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00006964 } else {
6965 ret = (arg1->floatval == arg2->floatval);
6966 }
Owen Taylor3473f882001-02-23 17:55:21 +00006967 break;
6968 case XPATH_USERS:
6969 case XPATH_POINT:
6970 case XPATH_RANGE:
6971 case XPATH_LOCATIONSET:
6972 TODO
6973 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006974 case XPATH_NODESET:
6975 case XPATH_XSLT_TREE:
6976 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006977 }
6978 break;
6979 case XPATH_STRING:
6980 switch (arg2->type) {
6981 case XPATH_UNDEFINED:
6982#ifdef DEBUG_EXPR
6983 xmlGenericError(xmlGenericErrorContext,
6984 "Equal: undefined\n");
6985#endif
6986 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006987 case XPATH_BOOLEAN:
6988 if ((arg1->stringval == NULL) ||
6989 (arg1->stringval[0] == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00006990 else
Owen Taylor3473f882001-02-23 17:55:21 +00006991 ret = 1;
6992 ret = (arg2->boolval == ret);
6993 break;
6994 case XPATH_STRING:
6995 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6996 break;
6997 case XPATH_NUMBER:
6998 valuePush(ctxt, arg1);
6999 xmlXPathNumberFunction(ctxt, 1);
7000 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007001 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00007002 if (xmlXPathIsNaN(arg1->floatval) ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00007003 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00007004 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007005 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7006 if (xmlXPathIsInf(arg2->floatval) == 1)
7007 ret = 1;
7008 else
7009 ret = 0;
7010 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7011 if (xmlXPathIsInf(arg2->floatval) == -1)
7012 ret = 1;
7013 else
7014 ret = 0;
7015 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7016 if (xmlXPathIsInf(arg1->floatval) == 1)
7017 ret = 1;
7018 else
7019 ret = 0;
7020 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7021 if (xmlXPathIsInf(arg1->floatval) == -1)
7022 ret = 1;
7023 else
7024 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007025 } else {
7026 ret = (arg1->floatval == arg2->floatval);
7027 }
Owen Taylor3473f882001-02-23 17:55:21 +00007028 break;
7029 case XPATH_USERS:
7030 case XPATH_POINT:
7031 case XPATH_RANGE:
7032 case XPATH_LOCATIONSET:
7033 TODO
7034 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007035 case XPATH_NODESET:
7036 case XPATH_XSLT_TREE:
7037 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007038 }
7039 break;
7040 case XPATH_USERS:
7041 case XPATH_POINT:
7042 case XPATH_RANGE:
7043 case XPATH_LOCATIONSET:
7044 TODO
7045 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007046 case XPATH_NODESET:
7047 case XPATH_XSLT_TREE:
7048 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007049 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007050 xmlXPathReleaseObject(ctxt->context, arg1);
7051 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007052 return(ret);
7053}
7054
William M. Brack0c022ad2002-07-12 00:56:01 +00007055/**
7056 * xmlXPathEqualValues:
7057 * @ctxt: the XPath Parser context
7058 *
7059 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7060 *
7061 * Returns 0 or 1 depending on the results of the test.
7062 */
7063int
7064xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7065 xmlXPathObjectPtr arg1, arg2, argtmp;
7066 int ret = 0;
7067
Daniel Veillard6128c012004-11-08 17:16:15 +00007068 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007069 arg2 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007070 arg1 = valuePop(ctxt);
7071 if ((arg1 == NULL) || (arg2 == NULL)) {
7072 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007073 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007074 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007075 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007076 XP_ERROR0(XPATH_INVALID_OPERAND);
7077 }
7078
7079 if (arg1 == arg2) {
7080#ifdef DEBUG_EXPR
7081 xmlGenericError(xmlGenericErrorContext,
7082 "Equal: by pointer\n");
7083#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00007084 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007085 return(1);
7086 }
7087
7088 /*
7089 *If either argument is a nodeset, it's a 'special case'
7090 */
7091 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7092 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7093 /*
7094 *Hack it to assure arg1 is the nodeset
7095 */
7096 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7097 argtmp = arg2;
7098 arg2 = arg1;
7099 arg1 = argtmp;
7100 }
7101 switch (arg2->type) {
7102 case XPATH_UNDEFINED:
7103#ifdef DEBUG_EXPR
7104 xmlGenericError(xmlGenericErrorContext,
7105 "Equal: undefined\n");
7106#endif
7107 break;
7108 case XPATH_NODESET:
7109 case XPATH_XSLT_TREE:
7110 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7111 break;
7112 case XPATH_BOOLEAN:
7113 if ((arg1->nodesetval == NULL) ||
7114 (arg1->nodesetval->nodeNr == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007115 else
William M. Brack0c022ad2002-07-12 00:56:01 +00007116 ret = 1;
7117 ret = (ret == arg2->boolval);
7118 break;
7119 case XPATH_NUMBER:
7120 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7121 break;
7122 case XPATH_STRING:
7123 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7124 break;
7125 case XPATH_USERS:
7126 case XPATH_POINT:
7127 case XPATH_RANGE:
7128 case XPATH_LOCATIONSET:
7129 TODO
7130 break;
7131 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007132 xmlXPathReleaseObject(ctxt->context, arg1);
7133 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007134 return(ret);
7135 }
7136
7137 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7138}
7139
7140/**
7141 * xmlXPathNotEqualValues:
7142 * @ctxt: the XPath Parser context
7143 *
7144 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7145 *
7146 * Returns 0 or 1 depending on the results of the test.
7147 */
7148int
7149xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7150 xmlXPathObjectPtr arg1, arg2, argtmp;
7151 int ret = 0;
7152
Daniel Veillard6128c012004-11-08 17:16:15 +00007153 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007154 arg2 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007155 arg1 = valuePop(ctxt);
7156 if ((arg1 == NULL) || (arg2 == NULL)) {
7157 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007158 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007159 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007160 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007161 XP_ERROR0(XPATH_INVALID_OPERAND);
7162 }
7163
7164 if (arg1 == arg2) {
7165#ifdef DEBUG_EXPR
7166 xmlGenericError(xmlGenericErrorContext,
7167 "NotEqual: by pointer\n");
7168#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007169 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007170 return(0);
7171 }
7172
7173 /*
7174 *If either argument is a nodeset, it's a 'special case'
7175 */
7176 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7177 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7178 /*
7179 *Hack it to assure arg1 is the nodeset
7180 */
7181 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7182 argtmp = arg2;
7183 arg2 = arg1;
7184 arg1 = argtmp;
7185 }
7186 switch (arg2->type) {
7187 case XPATH_UNDEFINED:
7188#ifdef DEBUG_EXPR
7189 xmlGenericError(xmlGenericErrorContext,
7190 "NotEqual: undefined\n");
7191#endif
7192 break;
7193 case XPATH_NODESET:
7194 case XPATH_XSLT_TREE:
7195 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7196 break;
7197 case XPATH_BOOLEAN:
7198 if ((arg1->nodesetval == NULL) ||
7199 (arg1->nodesetval->nodeNr == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007200 else
William M. Brack0c022ad2002-07-12 00:56:01 +00007201 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00007202 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00007203 break;
7204 case XPATH_NUMBER:
7205 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7206 break;
7207 case XPATH_STRING:
7208 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7209 break;
7210 case XPATH_USERS:
7211 case XPATH_POINT:
7212 case XPATH_RANGE:
7213 case XPATH_LOCATIONSET:
7214 TODO
7215 break;
7216 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007217 xmlXPathReleaseObject(ctxt->context, arg1);
7218 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007219 return(ret);
7220 }
7221
7222 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7223}
Owen Taylor3473f882001-02-23 17:55:21 +00007224
7225/**
7226 * xmlXPathCompareValues:
7227 * @ctxt: the XPath Parser context
7228 * @inf: less than (1) or greater than (0)
7229 * @strict: is the comparison strict
7230 *
Daniel Veillard45490ae2008-07-29 09:13:19 +00007231 * Implement the compare operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007232 * @arg1 < @arg2 (1, 1, ...
7233 * @arg1 <= @arg2 (1, 0, ...
7234 * @arg1 > @arg2 (0, 1, ...
7235 * @arg1 >= @arg2 (0, 0, ...
7236 *
7237 * When neither object to be compared is a node-set and the operator is
7238 * <=, <, >=, >, then the objects are compared by converted both objects
7239 * to numbers and comparing the numbers according to IEEE 754. The <
7240 * comparison will be true if and only if the first number is less than the
7241 * second number. The <= comparison will be true if and only if the first
7242 * number is less than or equal to the second number. The > comparison
7243 * will be true if and only if the first number is greater than the second
7244 * number. The >= comparison will be true if and only if the first number
7245 * is greater than or equal to the second number.
7246 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007247 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00007248 */
7249int
7250xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007251 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007252 xmlXPathObjectPtr arg1, arg2;
7253
Daniel Veillard6128c012004-11-08 17:16:15 +00007254 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007255 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007256 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007257 if ((arg1 == NULL) || (arg2 == NULL)) {
7258 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007259 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007260 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007261 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007262 XP_ERROR0(XPATH_INVALID_OPERAND);
7263 }
7264
William M. Brack0c022ad2002-07-12 00:56:01 +00007265 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7266 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
William M. Brackd6e347e2005-04-15 01:34:41 +00007267 /*
7268 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7269 * are not freed from within this routine; they will be freed from the
7270 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7271 */
William M. Brack0c022ad2002-07-12 00:56:01 +00007272 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7273 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007274 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007275 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00007276 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007277 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7278 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007279 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007280 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7281 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00007282 }
7283 }
7284 return(ret);
7285 }
7286
7287 if (arg1->type != XPATH_NUMBER) {
7288 valuePush(ctxt, arg1);
7289 xmlXPathNumberFunction(ctxt, 1);
7290 arg1 = valuePop(ctxt);
7291 }
7292 if (arg1->type != XPATH_NUMBER) {
7293 xmlXPathFreeObject(arg1);
7294 xmlXPathFreeObject(arg2);
7295 XP_ERROR0(XPATH_INVALID_OPERAND);
7296 }
7297 if (arg2->type != XPATH_NUMBER) {
7298 valuePush(ctxt, arg2);
7299 xmlXPathNumberFunction(ctxt, 1);
7300 arg2 = valuePop(ctxt);
7301 }
7302 if (arg2->type != XPATH_NUMBER) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007303 xmlXPathReleaseObject(ctxt->context, arg1);
7304 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007305 XP_ERROR0(XPATH_INVALID_OPERAND);
7306 }
7307 /*
7308 * Add tests for infinity and nan
7309 * => feedback on 3.4 for Inf and NaN
7310 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007311 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00007312 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007313 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007314 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007315 arg1i=xmlXPathIsInf(arg1->floatval);
7316 arg2i=xmlXPathIsInf(arg2->floatval);
7317 if (inf && strict) {
7318 if ((arg1i == -1 && arg2i != -1) ||
7319 (arg2i == 1 && arg1i != 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 ret = 1;
7330 } else if (arg1i == 0 && arg2i == 0) {
7331 ret = (arg1->floatval <= arg2->floatval);
7332 } else {
7333 ret = 0;
7334 }
7335 }
7336 else if (!inf && strict) {
7337 if ((arg1i == 1 && arg2i != 1) ||
7338 (arg2i == -1 && arg1i != -1)) {
7339 ret = 1;
7340 } else if (arg1i == 0 && arg2i == 0) {
7341 ret = (arg1->floatval > arg2->floatval);
7342 } else {
7343 ret = 0;
7344 }
7345 }
7346 else if (!inf && !strict) {
7347 if (arg1i == 1 || arg2i == -1) {
7348 ret = 1;
7349 } else if (arg1i == 0 && arg2i == 0) {
7350 ret = (arg1->floatval >= arg2->floatval);
7351 } else {
7352 ret = 0;
7353 }
7354 }
Daniel Veillard21458c82002-03-27 16:12:22 +00007355 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007356 xmlXPathReleaseObject(ctxt->context, arg1);
7357 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007358 return(ret);
7359}
7360
7361/**
7362 * xmlXPathValueFlipSign:
7363 * @ctxt: the XPath Parser context
7364 *
7365 * Implement the unary - operation on an XPath object
7366 * The numeric operators convert their operands to numbers as if
7367 * by calling the number function.
7368 */
7369void
7370xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007371 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007372 CAST_TO_NUMBER;
7373 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007374 if (xmlXPathIsNaN(ctxt->value->floatval))
7375 ctxt->value->floatval=xmlXPathNAN;
7376 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7377 ctxt->value->floatval=xmlXPathNINF;
7378 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7379 ctxt->value->floatval=xmlXPathPINF;
7380 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007381 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7382 ctxt->value->floatval = xmlXPathNZERO;
7383 else
7384 ctxt->value->floatval = 0;
7385 }
7386 else
7387 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00007388}
7389
7390/**
7391 * xmlXPathAddValues:
7392 * @ctxt: the XPath Parser context
7393 *
7394 * Implement the add operation on XPath objects:
7395 * The numeric operators convert their operands to numbers as if
7396 * by calling the number function.
7397 */
7398void
7399xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7400 xmlXPathObjectPtr arg;
7401 double val;
7402
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007403 arg = valuePop(ctxt);
7404 if (arg == NULL)
7405 XP_ERROR(XPATH_INVALID_OPERAND);
7406 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007407 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007408 CAST_TO_NUMBER;
7409 CHECK_TYPE(XPATH_NUMBER);
7410 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00007411}
7412
7413/**
7414 * xmlXPathSubValues:
7415 * @ctxt: the XPath Parser context
7416 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007417 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007418 * The numeric operators convert their operands to numbers as if
7419 * by calling the number function.
7420 */
7421void
7422xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7423 xmlXPathObjectPtr arg;
7424 double val;
7425
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007426 arg = valuePop(ctxt);
7427 if (arg == NULL)
7428 XP_ERROR(XPATH_INVALID_OPERAND);
7429 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007430 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007431 CAST_TO_NUMBER;
7432 CHECK_TYPE(XPATH_NUMBER);
7433 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007434}
7435
7436/**
7437 * xmlXPathMultValues:
7438 * @ctxt: the XPath Parser context
7439 *
7440 * Implement the multiply operation on XPath objects:
7441 * The numeric operators convert their operands to numbers as if
7442 * by calling the number function.
7443 */
7444void
7445xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7446 xmlXPathObjectPtr arg;
7447 double val;
7448
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007449 arg = valuePop(ctxt);
7450 if (arg == NULL)
7451 XP_ERROR(XPATH_INVALID_OPERAND);
7452 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007453 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007454 CAST_TO_NUMBER;
7455 CHECK_TYPE(XPATH_NUMBER);
7456 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007457}
7458
7459/**
7460 * xmlXPathDivValues:
7461 * @ctxt: the XPath Parser context
7462 *
7463 * Implement the div operation on XPath objects @arg1 / @arg2:
7464 * The numeric operators convert their operands to numbers as if
7465 * by calling the number function.
7466 */
7467void
7468xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7469 xmlXPathObjectPtr arg;
7470 double val;
7471
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007472 arg = valuePop(ctxt);
7473 if (arg == NULL)
7474 XP_ERROR(XPATH_INVALID_OPERAND);
7475 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007476 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007477 CAST_TO_NUMBER;
7478 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007479 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7480 ctxt->value->floatval = xmlXPathNAN;
7481 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007482 if (ctxt->value->floatval == 0)
7483 ctxt->value->floatval = xmlXPathNAN;
7484 else if (ctxt->value->floatval > 0)
7485 ctxt->value->floatval = xmlXPathNINF;
7486 else if (ctxt->value->floatval < 0)
7487 ctxt->value->floatval = xmlXPathPINF;
7488 }
7489 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007490 if (ctxt->value->floatval == 0)
7491 ctxt->value->floatval = xmlXPathNAN;
7492 else if (ctxt->value->floatval > 0)
7493 ctxt->value->floatval = xmlXPathPINF;
7494 else if (ctxt->value->floatval < 0)
7495 ctxt->value->floatval = xmlXPathNINF;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007496 } else
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007497 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007498}
7499
7500/**
7501 * xmlXPathModValues:
7502 * @ctxt: the XPath Parser context
7503 *
7504 * Implement the mod operation on XPath objects: @arg1 / @arg2
7505 * The numeric operators convert their operands to numbers as if
7506 * by calling the number function.
7507 */
7508void
7509xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7510 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00007511 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00007512
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007513 arg = valuePop(ctxt);
7514 if (arg == NULL)
7515 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007516 arg2 = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007517 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007518 CAST_TO_NUMBER;
7519 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007520 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00007521 if (arg2 == 0)
7522 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007523 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00007524 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007525 }
Owen Taylor3473f882001-02-23 17:55:21 +00007526}
7527
7528/************************************************************************
7529 * *
7530 * The traversal functions *
7531 * *
7532 ************************************************************************/
7533
Owen Taylor3473f882001-02-23 17:55:21 +00007534/*
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 */
7539typedef xmlNodePtr (*xmlXPathTraversalFunction)
7540 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7541
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007542/*
7543 * xmlXPathTraversalFunctionExt:
7544 * A traversal function enumerates nodes along an axis.
7545 * Initially it must be called with NULL, and it indicates
7546 * termination on the axis by returning NULL.
7547 * The context node of the traversal is specified via @contextNode.
7548 */
7549typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7550 (xmlNodePtr cur, xmlNodePtr contextNode);
7551
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00007552/*
7553 * xmlXPathNodeSetMergeFunction:
7554 * Used for merging node sets in xmlXPathCollectAndTest().
7555 */
7556typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7557 (xmlNodeSetPtr, xmlNodeSetPtr, int);
7558
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007559
Owen Taylor3473f882001-02-23 17:55:21 +00007560/**
7561 * xmlXPathNextSelf:
7562 * @ctxt: the XPath Parser context
7563 * @cur: the current node in the traversal
7564 *
7565 * Traversal function for the "self" direction
7566 * The self axis contains just the context node itself
7567 *
7568 * Returns the next element following that axis
7569 */
7570xmlNodePtr
7571xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007572 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007573 if (cur == NULL)
7574 return(ctxt->context->node);
7575 return(NULL);
7576}
7577
7578/**
7579 * xmlXPathNextChild:
7580 * @ctxt: the XPath Parser context
7581 * @cur: the current node in the traversal
7582 *
7583 * Traversal function for the "child" direction
7584 * The child axis contains the children of the context node in document order.
7585 *
7586 * Returns the next element following that axis
7587 */
7588xmlNodePtr
7589xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007590 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007591 if (cur == NULL) {
7592 if (ctxt->context->node == NULL) return(NULL);
7593 switch (ctxt->context->node->type) {
7594 case XML_ELEMENT_NODE:
7595 case XML_TEXT_NODE:
7596 case XML_CDATA_SECTION_NODE:
7597 case XML_ENTITY_REF_NODE:
7598 case XML_ENTITY_NODE:
7599 case XML_PI_NODE:
7600 case XML_COMMENT_NODE:
7601 case XML_NOTATION_NODE:
7602 case XML_DTD_NODE:
7603 return(ctxt->context->node->children);
7604 case XML_DOCUMENT_NODE:
7605 case XML_DOCUMENT_TYPE_NODE:
7606 case XML_DOCUMENT_FRAG_NODE:
7607 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007608#ifdef LIBXML_DOCB_ENABLED
7609 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007610#endif
7611 return(((xmlDocPtr) ctxt->context->node)->children);
7612 case XML_ELEMENT_DECL:
7613 case XML_ATTRIBUTE_DECL:
7614 case XML_ENTITY_DECL:
7615 case XML_ATTRIBUTE_NODE:
7616 case XML_NAMESPACE_DECL:
7617 case XML_XINCLUDE_START:
7618 case XML_XINCLUDE_END:
7619 return(NULL);
7620 }
7621 return(NULL);
7622 }
7623 if ((cur->type == XML_DOCUMENT_NODE) ||
7624 (cur->type == XML_HTML_DOCUMENT_NODE))
7625 return(NULL);
7626 return(cur->next);
7627}
7628
7629/**
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00007630 * xmlXPathNextChildElement:
7631 * @ctxt: the XPath Parser context
7632 * @cur: the current node in the traversal
7633 *
7634 * Traversal function for the "child" direction and nodes of type element.
7635 * The child axis contains the children of the context node in document order.
7636 *
7637 * Returns the next element following that axis
7638 */
7639static xmlNodePtr
7640xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7641 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7642 if (cur == NULL) {
7643 cur = ctxt->context->node;
7644 if (cur == NULL) return(NULL);
7645 /*
7646 * Get the first element child.
7647 */
7648 switch (cur->type) {
7649 case XML_ELEMENT_NODE:
7650 case XML_DOCUMENT_FRAG_NODE:
7651 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7652 case XML_ENTITY_NODE:
7653 cur = cur->children;
7654 if (cur != NULL) {
7655 if (cur->type == XML_ELEMENT_NODE)
7656 return(cur);
7657 do {
7658 cur = cur->next;
7659 } while ((cur != NULL) &&
7660 (cur->type != XML_ELEMENT_NODE));
7661 return(cur);
7662 }
7663 return(NULL);
7664 case XML_DOCUMENT_NODE:
7665 case XML_HTML_DOCUMENT_NODE:
7666#ifdef LIBXML_DOCB_ENABLED
7667 case XML_DOCB_DOCUMENT_NODE:
7668#endif
7669 return(xmlDocGetRootElement((xmlDocPtr) cur));
7670 default:
7671 return(NULL);
7672 }
7673 return(NULL);
7674 }
7675 /*
7676 * Get the next sibling element node.
7677 */
7678 switch (cur->type) {
7679 case XML_ELEMENT_NODE:
7680 case XML_TEXT_NODE:
7681 case XML_ENTITY_REF_NODE:
7682 case XML_ENTITY_NODE:
7683 case XML_CDATA_SECTION_NODE:
7684 case XML_PI_NODE:
7685 case XML_COMMENT_NODE:
7686 case XML_XINCLUDE_END:
7687 break;
7688 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7689 default:
7690 return(NULL);
7691 }
7692 if (cur->next != NULL) {
7693 if (cur->next->type == XML_ELEMENT_NODE)
7694 return(cur->next);
7695 cur = cur->next;
7696 do {
7697 cur = cur->next;
7698 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7699 return(cur);
7700 }
7701 return(NULL);
7702}
7703
7704/**
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007705 * xmlXPathNextDescendantOrSelfElemParent:
7706 * @ctxt: the XPath Parser context
7707 * @cur: the current node in the traversal
7708 *
7709 * Traversal function for the "descendant-or-self" axis.
7710 * Additionally it returns only nodes which can be parents of
7711 * element nodes.
7712 *
7713 *
7714 * Returns the next element following that axis
7715 */
7716static xmlNodePtr
7717xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7718 xmlNodePtr contextNode)
7719{
7720 if (cur == NULL) {
7721 if (contextNode == NULL)
7722 return(NULL);
7723 switch (contextNode->type) {
7724 case XML_ELEMENT_NODE:
7725 case XML_XINCLUDE_START:
7726 case XML_DOCUMENT_FRAG_NODE:
7727 case XML_DOCUMENT_NODE:
7728#ifdef LIBXML_DOCB_ENABLED
7729 case XML_DOCB_DOCUMENT_NODE:
7730#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00007731 case XML_HTML_DOCUMENT_NODE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007732 return(contextNode);
7733 default:
Daniel Veillard45490ae2008-07-29 09:13:19 +00007734 return(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007735 }
7736 return(NULL);
7737 } else {
7738 xmlNodePtr start = cur;
7739
7740 while (cur != NULL) {
7741 switch (cur->type) {
7742 case XML_ELEMENT_NODE:
7743 /* TODO: OK to have XInclude here? */
7744 case XML_XINCLUDE_START:
Daniel Veillard45490ae2008-07-29 09:13:19 +00007745 case XML_DOCUMENT_FRAG_NODE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007746 if (cur != start)
7747 return(cur);
7748 if (cur->children != NULL) {
7749 cur = cur->children;
7750 continue;
7751 }
7752 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007753 /* Not sure if we need those here. */
7754 case XML_DOCUMENT_NODE:
Daniel Veillard17970a72006-10-26 08:55:47 +00007755#ifdef LIBXML_DOCB_ENABLED
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007756 case XML_DOCB_DOCUMENT_NODE:
7757#endif
7758 case XML_HTML_DOCUMENT_NODE:
7759 if (cur != start)
7760 return(cur);
7761 return(xmlDocGetRootElement((xmlDocPtr) cur));
7762 default:
7763 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007764 }
7765
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007766next_sibling:
7767 if ((cur == NULL) || (cur == contextNode))
Daniel Veillard45490ae2008-07-29 09:13:19 +00007768 return(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007769 if (cur->next != NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00007770 cur = cur->next;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007771 } else {
7772 cur = cur->parent;
7773 goto next_sibling;
7774 }
7775 }
7776 }
7777 return(NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007778}
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007779
7780/**
Owen Taylor3473f882001-02-23 17:55:21 +00007781 * xmlXPathNextDescendant:
7782 * @ctxt: the XPath Parser context
7783 * @cur: the current node in the traversal
7784 *
7785 * Traversal function for the "descendant" direction
7786 * the descendant axis contains the descendants of the context node in document
7787 * order; a descendant is a child or a child of a child and so on.
7788 *
7789 * Returns the next element following that axis
7790 */
7791xmlNodePtr
7792xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007793 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007794 if (cur == NULL) {
7795 if (ctxt->context->node == NULL)
7796 return(NULL);
7797 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7798 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7799 return(NULL);
7800
7801 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7802 return(ctxt->context->doc->children);
7803 return(ctxt->context->node->children);
7804 }
7805
Daniel Veillard567e1b42001-08-01 15:53:47 +00007806 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007807 /*
7808 * Do not descend on entities declarations
7809 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00007810 if (cur->children->type != XML_ENTITY_DECL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007811 cur = cur->children;
7812 /*
7813 * Skip DTDs
7814 */
7815 if (cur->type != XML_DTD_NODE)
7816 return(cur);
7817 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00007818 }
7819
7820 if (cur == ctxt->context->node) return(NULL);
7821
Daniel Veillard68e9e742002-11-16 15:35:11 +00007822 while (cur->next != NULL) {
7823 cur = cur->next;
7824 if ((cur->type != XML_ENTITY_DECL) &&
7825 (cur->type != XML_DTD_NODE))
7826 return(cur);
7827 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00007828
Owen Taylor3473f882001-02-23 17:55:21 +00007829 do {
7830 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00007831 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00007832 if (cur == ctxt->context->node) return(NULL);
7833 if (cur->next != NULL) {
7834 cur = cur->next;
7835 return(cur);
7836 }
7837 } while (cur != NULL);
7838 return(cur);
7839}
7840
7841/**
7842 * xmlXPathNextDescendantOrSelf:
7843 * @ctxt: the XPath Parser context
7844 * @cur: the current node in the traversal
7845 *
7846 * Traversal function for the "descendant-or-self" direction
7847 * the descendant-or-self axis contains the context node and the descendants
7848 * of the context node in document order; thus the context node is the first
7849 * node on the axis, and the first child of the context node is the second node
7850 * on the axis
7851 *
7852 * Returns the next element following that axis
7853 */
7854xmlNodePtr
7855xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007856 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007857 if (cur == NULL) {
7858 if (ctxt->context->node == NULL)
7859 return(NULL);
7860 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7861 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7862 return(NULL);
7863 return(ctxt->context->node);
7864 }
7865
7866 return(xmlXPathNextDescendant(ctxt, cur));
7867}
7868
7869/**
7870 * xmlXPathNextParent:
7871 * @ctxt: the XPath Parser context
7872 * @cur: the current node in the traversal
7873 *
7874 * Traversal function for the "parent" direction
7875 * The parent axis contains the parent of the context node, if there is one.
7876 *
7877 * Returns the next element following that axis
7878 */
7879xmlNodePtr
7880xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007881 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007882 /*
7883 * the parent of an attribute or namespace node is the element
7884 * to which the attribute or namespace node is attached
7885 * Namespace handling !!!
7886 */
7887 if (cur == NULL) {
7888 if (ctxt->context->node == NULL) return(NULL);
7889 switch (ctxt->context->node->type) {
7890 case XML_ELEMENT_NODE:
7891 case XML_TEXT_NODE:
7892 case XML_CDATA_SECTION_NODE:
7893 case XML_ENTITY_REF_NODE:
7894 case XML_ENTITY_NODE:
7895 case XML_PI_NODE:
7896 case XML_COMMENT_NODE:
7897 case XML_NOTATION_NODE:
7898 case XML_DTD_NODE:
7899 case XML_ELEMENT_DECL:
7900 case XML_ATTRIBUTE_DECL:
7901 case XML_XINCLUDE_START:
7902 case XML_XINCLUDE_END:
7903 case XML_ENTITY_DECL:
7904 if (ctxt->context->node->parent == NULL)
7905 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007906 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007907 ((ctxt->context->node->parent->name[0] == ' ') ||
7908 (xmlStrEqual(ctxt->context->node->parent->name,
7909 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007910 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007911 return(ctxt->context->node->parent);
7912 case XML_ATTRIBUTE_NODE: {
7913 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7914
7915 return(att->parent);
7916 }
7917 case XML_DOCUMENT_NODE:
7918 case XML_DOCUMENT_TYPE_NODE:
7919 case XML_DOCUMENT_FRAG_NODE:
7920 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007921#ifdef LIBXML_DOCB_ENABLED
7922 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007923#endif
7924 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007925 case XML_NAMESPACE_DECL: {
7926 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007927
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007928 if ((ns->next != NULL) &&
7929 (ns->next->type != XML_NAMESPACE_DECL))
7930 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00007931 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007932 }
Owen Taylor3473f882001-02-23 17:55:21 +00007933 }
7934 }
7935 return(NULL);
7936}
7937
7938/**
7939 * xmlXPathNextAncestor:
7940 * @ctxt: the XPath Parser context
7941 * @cur: the current node in the traversal
7942 *
7943 * Traversal function for the "ancestor" direction
7944 * the ancestor axis contains the ancestors of the context node; the ancestors
7945 * of the context node consist of the parent of context node and the parent's
7946 * parent and so on; the nodes are ordered in reverse document order; thus the
7947 * parent is the first node on the axis, and the parent's parent is the second
7948 * node on the axis
7949 *
7950 * Returns the next element following that axis
7951 */
7952xmlNodePtr
7953xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007954 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007955 /*
7956 * the parent of an attribute or namespace node is the element
7957 * to which the attribute or namespace node is attached
7958 * !!!!!!!!!!!!!
7959 */
7960 if (cur == NULL) {
7961 if (ctxt->context->node == NULL) return(NULL);
7962 switch (ctxt->context->node->type) {
7963 case XML_ELEMENT_NODE:
7964 case XML_TEXT_NODE:
7965 case XML_CDATA_SECTION_NODE:
7966 case XML_ENTITY_REF_NODE:
7967 case XML_ENTITY_NODE:
7968 case XML_PI_NODE:
7969 case XML_COMMENT_NODE:
7970 case XML_DTD_NODE:
7971 case XML_ELEMENT_DECL:
7972 case XML_ATTRIBUTE_DECL:
7973 case XML_ENTITY_DECL:
7974 case XML_NOTATION_NODE:
7975 case XML_XINCLUDE_START:
7976 case XML_XINCLUDE_END:
7977 if (ctxt->context->node->parent == NULL)
7978 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007979 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007980 ((ctxt->context->node->parent->name[0] == ' ') ||
7981 (xmlStrEqual(ctxt->context->node->parent->name,
7982 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007983 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007984 return(ctxt->context->node->parent);
7985 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007986 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00007987
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007988 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00007989 }
7990 case XML_DOCUMENT_NODE:
7991 case XML_DOCUMENT_TYPE_NODE:
7992 case XML_DOCUMENT_FRAG_NODE:
7993 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007994#ifdef LIBXML_DOCB_ENABLED
7995 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007996#endif
7997 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007998 case XML_NAMESPACE_DECL: {
7999 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008000
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008001 if ((ns->next != NULL) &&
8002 (ns->next->type != XML_NAMESPACE_DECL))
8003 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00008004 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00008005 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008006 }
Owen Taylor3473f882001-02-23 17:55:21 +00008007 }
8008 return(NULL);
8009 }
8010 if (cur == ctxt->context->doc->children)
8011 return((xmlNodePtr) ctxt->context->doc);
8012 if (cur == (xmlNodePtr) ctxt->context->doc)
8013 return(NULL);
8014 switch (cur->type) {
8015 case XML_ELEMENT_NODE:
8016 case XML_TEXT_NODE:
8017 case XML_CDATA_SECTION_NODE:
8018 case XML_ENTITY_REF_NODE:
8019 case XML_ENTITY_NODE:
8020 case XML_PI_NODE:
8021 case XML_COMMENT_NODE:
8022 case XML_NOTATION_NODE:
8023 case XML_DTD_NODE:
8024 case XML_ELEMENT_DECL:
8025 case XML_ATTRIBUTE_DECL:
8026 case XML_ENTITY_DECL:
8027 case XML_XINCLUDE_START:
8028 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008029 if (cur->parent == NULL)
8030 return(NULL);
8031 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00008032 ((cur->parent->name[0] == ' ') ||
8033 (xmlStrEqual(cur->parent->name,
8034 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008035 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008036 return(cur->parent);
8037 case XML_ATTRIBUTE_NODE: {
8038 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
8039
8040 return(att->parent);
8041 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008042 case XML_NAMESPACE_DECL: {
8043 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008044
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008045 if ((ns->next != NULL) &&
8046 (ns->next->type != XML_NAMESPACE_DECL))
8047 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00008048 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008049 return(NULL);
8050 }
Owen Taylor3473f882001-02-23 17:55:21 +00008051 case XML_DOCUMENT_NODE:
8052 case XML_DOCUMENT_TYPE_NODE:
8053 case XML_DOCUMENT_FRAG_NODE:
8054 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00008055#ifdef LIBXML_DOCB_ENABLED
8056 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00008057#endif
8058 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008059 }
8060 return(NULL);
8061}
8062
8063/**
8064 * xmlXPathNextAncestorOrSelf:
8065 * @ctxt: the XPath Parser context
8066 * @cur: the current node in the traversal
8067 *
8068 * Traversal function for the "ancestor-or-self" direction
8069 * he ancestor-or-self axis contains the context node and ancestors of
8070 * the context node in reverse document order; thus the context node is
8071 * the first node on the axis, and the context node's parent the second;
8072 * parent here is defined the same as with the parent axis.
8073 *
8074 * Returns the next element following that axis
8075 */
8076xmlNodePtr
8077xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008078 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008079 if (cur == NULL)
8080 return(ctxt->context->node);
8081 return(xmlXPathNextAncestor(ctxt, cur));
8082}
8083
8084/**
8085 * xmlXPathNextFollowingSibling:
8086 * @ctxt: the XPath Parser context
8087 * @cur: the current node in the traversal
8088 *
8089 * Traversal function for the "following-sibling" direction
8090 * The following-sibling axis contains the following siblings of the context
8091 * node in document order.
8092 *
8093 * Returns the next element following that axis
8094 */
8095xmlNodePtr
8096xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008097 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008098 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8099 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8100 return(NULL);
8101 if (cur == (xmlNodePtr) ctxt->context->doc)
8102 return(NULL);
8103 if (cur == NULL)
8104 return(ctxt->context->node->next);
8105 return(cur->next);
8106}
8107
8108/**
8109 * xmlXPathNextPrecedingSibling:
8110 * @ctxt: the XPath Parser context
8111 * @cur: the current node in the traversal
8112 *
8113 * Traversal function for the "preceding-sibling" direction
8114 * The preceding-sibling axis contains the preceding siblings of the context
8115 * node in reverse document order; the first preceding sibling is first on the
8116 * axis; the sibling preceding that node is the second on the axis and so on.
8117 *
8118 * Returns the next element following that axis
8119 */
8120xmlNodePtr
8121xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008122 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008123 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8124 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8125 return(NULL);
8126 if (cur == (xmlNodePtr) ctxt->context->doc)
8127 return(NULL);
8128 if (cur == NULL)
8129 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008130 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8131 cur = cur->prev;
8132 if (cur == NULL)
8133 return(ctxt->context->node->prev);
8134 }
Owen Taylor3473f882001-02-23 17:55:21 +00008135 return(cur->prev);
8136}
8137
8138/**
8139 * xmlXPathNextFollowing:
8140 * @ctxt: the XPath Parser context
8141 * @cur: the current node in the traversal
8142 *
8143 * Traversal function for the "following" direction
8144 * The following axis contains all nodes in the same document as the context
8145 * node that are after the context node in document order, excluding any
8146 * descendants and excluding attribute nodes and namespace nodes; the nodes
8147 * are ordered in document order
8148 *
8149 * Returns the next element following that axis
8150 */
8151xmlNodePtr
8152xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008153 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008154 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
8155 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8156 return(cur->children);
8157
8158 if (cur == NULL) {
8159 cur = ctxt->context->node;
8160 if (cur->type == XML_NAMESPACE_DECL)
Daniel Veillard91d19752010-10-15 14:30:52 +02008161 return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008162 if (cur->type == XML_ATTRIBUTE_NODE)
8163 cur = cur->parent;
Daniel Veillard91d19752010-10-15 14:30:52 +02008164 }
Owen Taylor3473f882001-02-23 17:55:21 +00008165 if (cur == NULL) return(NULL) ; /* ERROR */
8166 if (cur->next != NULL) return(cur->next) ;
8167 do {
8168 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00008169 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00008170 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8171 if (cur->next != NULL) return(cur->next);
8172 } while (cur != NULL);
8173 return(cur);
8174}
8175
8176/*
8177 * xmlXPathIsAncestor:
8178 * @ancestor: the ancestor node
8179 * @node: the current node
8180 *
8181 * Check that @ancestor is a @node's ancestor
8182 *
8183 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8184 */
8185static int
8186xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8187 if ((ancestor == NULL) || (node == NULL)) return(0);
8188 /* nodes need to be in the same document */
8189 if (ancestor->doc != node->doc) return(0);
8190 /* avoid searching if ancestor or node is the root node */
8191 if (ancestor == (xmlNodePtr) node->doc) return(1);
8192 if (node == (xmlNodePtr) ancestor->doc) return(0);
8193 while (node->parent != NULL) {
8194 if (node->parent == ancestor)
8195 return(1);
8196 node = node->parent;
8197 }
8198 return(0);
8199}
8200
8201/**
8202 * xmlXPathNextPreceding:
8203 * @ctxt: the XPath Parser context
8204 * @cur: the current node in the traversal
8205 *
8206 * Traversal function for the "preceding" direction
8207 * the preceding axis contains all nodes in the same document as the context
8208 * node that are before the context node in document order, excluding any
8209 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8210 * ordered in reverse document order
8211 *
8212 * Returns the next element following that axis
8213 */
8214xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00008215xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8216{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008217 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008218 if (cur == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008219 cur = ctxt->context->node;
Daniel Veillardea90b892010-10-22 15:50:50 +02008220 if (cur->type == XML_NAMESPACE_DECL)
8221 return(NULL);
8222 if (cur->type == XML_ATTRIBUTE_NODE)
8223 return(cur->parent);
8224 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00008225 if (cur == NULL)
8226 return (NULL);
8227 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8228 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00008229 do {
8230 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008231 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8232 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008233 }
8234
8235 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008236 if (cur == NULL)
8237 return (NULL);
8238 if (cur == ctxt->context->doc->children)
8239 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008240 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00008241 return (cur);
8242}
8243
8244/**
8245 * xmlXPathNextPrecedingInternal:
8246 * @ctxt: the XPath Parser context
8247 * @cur: the current node in the traversal
8248 *
8249 * Traversal function for the "preceding" direction
8250 * the preceding axis contains all nodes in the same document as the context
8251 * node that are before the context node in document order, excluding any
8252 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8253 * ordered in reverse document order
Daniel Veillard45490ae2008-07-29 09:13:19 +00008254 * This is a faster implementation but internal only since it requires a
Daniel Veillardf06307e2001-07-03 10:35:50 +00008255 * state kept in the parser context: ctxt->ancestor.
8256 *
8257 * Returns the next element following that axis
8258 */
8259static xmlNodePtr
8260xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8261 xmlNodePtr cur)
8262{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008263 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008264 if (cur == NULL) {
8265 cur = ctxt->context->node;
8266 if (cur == NULL)
8267 return (NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008268 if (cur->type == XML_NAMESPACE_DECL)
8269 return (NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008270 ctxt->ancestor = cur->parent;
8271 }
8272 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8273 cur = cur->prev;
8274 while (cur->prev == NULL) {
8275 cur = cur->parent;
8276 if (cur == NULL)
8277 return (NULL);
8278 if (cur == ctxt->context->doc->children)
8279 return (NULL);
8280 if (cur != ctxt->ancestor)
8281 return (cur);
8282 ctxt->ancestor = cur->parent;
8283 }
8284 cur = cur->prev;
8285 while (cur->last != NULL)
8286 cur = cur->last;
8287 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008288}
8289
8290/**
8291 * xmlXPathNextNamespace:
8292 * @ctxt: the XPath Parser context
8293 * @cur: the current attribute in the traversal
8294 *
8295 * Traversal function for the "namespace" direction
8296 * the namespace axis contains the namespace nodes of the context node;
8297 * the order of nodes on this axis is implementation-defined; the axis will
8298 * be empty unless the context node is an element
8299 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008300 * We keep the XML namespace node at the end of the list.
8301 *
Owen Taylor3473f882001-02-23 17:55:21 +00008302 * Returns the next element following that axis
8303 */
8304xmlNodePtr
8305xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008306 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008307 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00008308 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008309 if (ctxt->context->tmpNsList != NULL)
8310 xmlFree(ctxt->context->tmpNsList);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008311 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00008312 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008313 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00008314 if (ctxt->context->tmpNsList != NULL) {
8315 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8316 ctxt->context->tmpNsNr++;
8317 }
8318 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008319 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008320 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00008321 if (ctxt->context->tmpNsNr > 0) {
8322 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8323 } else {
8324 if (ctxt->context->tmpNsList != NULL)
8325 xmlFree(ctxt->context->tmpNsList);
8326 ctxt->context->tmpNsList = NULL;
8327 return(NULL);
8328 }
Owen Taylor3473f882001-02-23 17:55:21 +00008329}
8330
8331/**
8332 * xmlXPathNextAttribute:
8333 * @ctxt: the XPath Parser context
8334 * @cur: the current attribute in the traversal
8335 *
8336 * Traversal function for the "attribute" direction
8337 * TODO: support DTD inherited default attributes
8338 *
8339 * Returns the next element following that axis
8340 */
8341xmlNodePtr
8342xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008343 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00008344 if (ctxt->context->node == NULL)
8345 return(NULL);
8346 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8347 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008348 if (cur == NULL) {
8349 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8350 return(NULL);
8351 return((xmlNodePtr)ctxt->context->node->properties);
8352 }
8353 return((xmlNodePtr)cur->next);
8354}
8355
8356/************************************************************************
8357 * *
8358 * NodeTest Functions *
8359 * *
8360 ************************************************************************/
8361
Owen Taylor3473f882001-02-23 17:55:21 +00008362#define IS_FUNCTION 200
8363
Owen Taylor3473f882001-02-23 17:55:21 +00008364
8365/************************************************************************
8366 * *
8367 * Implicit tree core function library *
8368 * *
8369 ************************************************************************/
8370
8371/**
8372 * xmlXPathRoot:
8373 * @ctxt: the XPath Parser context
8374 *
8375 * Initialize the context to the root of the document
8376 */
8377void
8378xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008379 if ((ctxt == NULL) || (ctxt->context == NULL))
8380 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008381 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008382 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8383 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008384}
8385
8386/************************************************************************
8387 * *
8388 * The explicit core function library *
8389 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8390 * *
8391 ************************************************************************/
8392
8393
8394/**
8395 * xmlXPathLastFunction:
8396 * @ctxt: the XPath Parser context
8397 * @nargs: the number of arguments
8398 *
8399 * Implement the last() XPath function
8400 * number last()
8401 * The last function returns the number of nodes in the context node list.
8402 */
8403void
8404xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8405 CHECK_ARITY(0);
8406 if (ctxt->context->contextSize >= 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008407 valuePush(ctxt,
8408 xmlXPathCacheNewFloat(ctxt->context,
8409 (double) ctxt->context->contextSize));
Owen Taylor3473f882001-02-23 17:55:21 +00008410#ifdef DEBUG_EXPR
8411 xmlGenericError(xmlGenericErrorContext,
8412 "last() : %d\n", ctxt->context->contextSize);
8413#endif
8414 } else {
8415 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8416 }
8417}
8418
8419/**
8420 * xmlXPathPositionFunction:
8421 * @ctxt: the XPath Parser context
8422 * @nargs: the number of arguments
8423 *
8424 * Implement the position() XPath function
8425 * number position()
8426 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008427 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00008428 * will be equal to last().
8429 */
8430void
8431xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8432 CHECK_ARITY(0);
8433 if (ctxt->context->proximityPosition >= 0) {
8434 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008435 xmlXPathCacheNewFloat(ctxt->context,
8436 (double) ctxt->context->proximityPosition));
Owen Taylor3473f882001-02-23 17:55:21 +00008437#ifdef DEBUG_EXPR
8438 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8439 ctxt->context->proximityPosition);
8440#endif
8441 } else {
8442 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8443 }
8444}
8445
8446/**
8447 * xmlXPathCountFunction:
8448 * @ctxt: the XPath Parser context
8449 * @nargs: the number of arguments
8450 *
8451 * Implement the count() XPath function
8452 * number count(node-set)
8453 */
8454void
8455xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8456 xmlXPathObjectPtr cur;
8457
8458 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008459 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008460 ((ctxt->value->type != XPATH_NODESET) &&
8461 (ctxt->value->type != XPATH_XSLT_TREE)))
8462 XP_ERROR(XPATH_INVALID_TYPE);
8463 cur = valuePop(ctxt);
8464
Daniel Veillard911f49a2001-04-07 15:39:35 +00008465 if ((cur == NULL) || (cur->nodesetval == NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008466 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00008467 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008468 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8469 (double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00008470 } else {
8471 if ((cur->nodesetval->nodeNr != 1) ||
8472 (cur->nodesetval->nodeTab == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008473 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00008474 } else {
8475 xmlNodePtr tmp;
8476 int i = 0;
8477
8478 tmp = cur->nodesetval->nodeTab[0];
8479 if (tmp != NULL) {
8480 tmp = tmp->children;
8481 while (tmp != NULL) {
8482 tmp = tmp->next;
8483 i++;
8484 }
8485 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008486 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
Daniel Veillardfe703322001-08-14 12:18:09 +00008487 }
8488 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008489 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008490}
8491
8492/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008493 * xmlXPathGetElementsByIds:
8494 * @doc: the document
8495 * @ids: a whitespace separated list of IDs
8496 *
8497 * Selects elements by their unique ID.
8498 *
8499 * Returns a node-set of selected elements.
8500 */
8501static xmlNodeSetPtr
8502xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8503 xmlNodeSetPtr ret;
8504 const xmlChar *cur = ids;
8505 xmlChar *ID;
8506 xmlAttrPtr attr;
8507 xmlNodePtr elem = NULL;
8508
Daniel Veillard7a985a12003-07-06 17:57:42 +00008509 if (ids == NULL) return(NULL);
8510
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008511 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00008512 if (ret == NULL)
8513 return(ret);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008514
William M. Brack76e95df2003-10-18 16:20:14 +00008515 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008516 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008517 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00008518 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008519
8520 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00008521 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00008522 /*
8523 * We used to check the fact that the value passed
8524 * was an NCName, but this generated much troubles for
8525 * me and Aleksey Sanin, people blatantly violated that
8526 * constaint, like Visa3D spec.
8527 * if (xmlValidateNCName(ID, 1) == 0)
8528 */
8529 attr = xmlGetID(doc, ID);
8530 if (attr != NULL) {
8531 if (attr->type == XML_ATTRIBUTE_NODE)
8532 elem = attr->parent;
8533 else if (attr->type == XML_ELEMENT_NODE)
8534 elem = (xmlNodePtr) attr;
8535 else
8536 elem = NULL;
8537 if (elem != NULL)
8538 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00008539 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008540 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00008541 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008542
William M. Brack76e95df2003-10-18 16:20:14 +00008543 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008544 ids = cur;
8545 }
8546 return(ret);
8547}
8548
8549/**
Owen Taylor3473f882001-02-23 17:55:21 +00008550 * xmlXPathIdFunction:
8551 * @ctxt: the XPath Parser context
8552 * @nargs: the number of arguments
8553 *
8554 * Implement the id() XPath function
8555 * node-set id(object)
8556 * The id function selects elements by their unique ID
8557 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8558 * then the result is the union of the result of applying id to the
8559 * string value of each of the nodes in the argument node-set. When the
8560 * argument to id is of any other type, the argument is converted to a
8561 * string as if by a call to the string function; the string is split
8562 * into a whitespace-separated list of tokens (whitespace is any sequence
8563 * of characters matching the production S); the result is a node-set
8564 * containing the elements in the same document as the context node that
8565 * have a unique ID equal to any of the tokens in the list.
8566 */
8567void
8568xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008569 xmlChar *tokens;
8570 xmlNodeSetPtr ret;
8571 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00008572
8573 CHECK_ARITY(1);
8574 obj = valuePop(ctxt);
8575 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00008576 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008577 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00008578 int i;
8579
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008580 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00008581 /*
8582 * FIXME -- in an out-of-memory condition this will behave badly.
8583 * The solution is not clear -- we already popped an item from
8584 * ctxt, so the object is in a corrupt state.
8585 */
Owen Taylor3473f882001-02-23 17:55:21 +00008586
Daniel Veillard911f49a2001-04-07 15:39:35 +00008587 if (obj->nodesetval != NULL) {
8588 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008589 tokens =
8590 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8591 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8592 ret = xmlXPathNodeSetMerge(ret, ns);
8593 xmlXPathFreeNodeSet(ns);
8594 if (tokens != NULL)
8595 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00008596 }
Owen Taylor3473f882001-02-23 17:55:21 +00008597 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008598 xmlXPathReleaseObject(ctxt->context, obj);
8599 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00008600 return;
8601 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008602 obj = xmlXPathCacheConvertString(ctxt->context, obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008603 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008604 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008605 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00008606 return;
8607}
8608
8609/**
8610 * xmlXPathLocalNameFunction:
8611 * @ctxt: the XPath Parser context
8612 * @nargs: the number of arguments
8613 *
8614 * Implement the local-name() XPath function
8615 * string local-name(node-set?)
8616 * The local-name function returns a string containing the local part
8617 * of the name of the node in the argument node-set that is first in
8618 * document order. If the node-set is empty or the first node has no
8619 * name, an empty string is returned. If the argument is omitted it
8620 * defaults to the context node.
8621 */
8622void
8623xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8624 xmlXPathObjectPtr cur;
8625
Daniel Veillarda82b1822004-11-08 16:24:57 +00008626 if (ctxt == NULL) return;
8627
Owen Taylor3473f882001-02-23 17:55:21 +00008628 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008629 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8630 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008631 nargs = 1;
8632 }
8633
8634 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008635 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008636 ((ctxt->value->type != XPATH_NODESET) &&
8637 (ctxt->value->type != XPATH_XSLT_TREE)))
8638 XP_ERROR(XPATH_INVALID_TYPE);
8639 cur = valuePop(ctxt);
8640
Daniel Veillard911f49a2001-04-07 15:39:35 +00008641 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008642 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008643 } else {
8644 int i = 0; /* Should be first in document order !!!!! */
8645 switch (cur->nodesetval->nodeTab[i]->type) {
8646 case XML_ELEMENT_NODE:
8647 case XML_ATTRIBUTE_NODE:
8648 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008649 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008650 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008651 else
8652 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008653 xmlXPathCacheNewString(ctxt->context,
8654 cur->nodesetval->nodeTab[i]->name));
Owen Taylor3473f882001-02-23 17:55:21 +00008655 break;
8656 case XML_NAMESPACE_DECL:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008657 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008658 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8659 break;
8660 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008661 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008662 }
8663 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008664 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008665}
8666
8667/**
8668 * xmlXPathNamespaceURIFunction:
8669 * @ctxt: the XPath Parser context
8670 * @nargs: the number of arguments
8671 *
8672 * Implement the namespace-uri() XPath function
8673 * string namespace-uri(node-set?)
8674 * The namespace-uri function returns a string containing the
8675 * namespace URI of the expanded name of the node in the argument
8676 * node-set that is first in document order. If the node-set is empty,
8677 * the first node has no name, or the expanded name has no namespace
8678 * URI, an empty string is returned. If the argument is omitted it
8679 * defaults to the context node.
8680 */
8681void
8682xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8683 xmlXPathObjectPtr cur;
8684
Daniel Veillarda82b1822004-11-08 16:24:57 +00008685 if (ctxt == NULL) return;
8686
Owen Taylor3473f882001-02-23 17:55:21 +00008687 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008688 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8689 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008690 nargs = 1;
8691 }
8692 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008693 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008694 ((ctxt->value->type != XPATH_NODESET) &&
8695 (ctxt->value->type != XPATH_XSLT_TREE)))
8696 XP_ERROR(XPATH_INVALID_TYPE);
8697 cur = valuePop(ctxt);
8698
Daniel Veillard911f49a2001-04-07 15:39:35 +00008699 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008700 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008701 } else {
8702 int i = 0; /* Should be first in document order !!!!! */
8703 switch (cur->nodesetval->nodeTab[i]->type) {
8704 case XML_ELEMENT_NODE:
8705 case XML_ATTRIBUTE_NODE:
8706 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008707 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008708 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008709 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008710 cur->nodesetval->nodeTab[i]->ns->href));
8711 break;
8712 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008713 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008714 }
8715 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008716 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008717}
8718
8719/**
8720 * xmlXPathNameFunction:
8721 * @ctxt: the XPath Parser context
8722 * @nargs: the number of arguments
8723 *
8724 * Implement the name() XPath function
8725 * string name(node-set?)
8726 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008727 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00008728 * order. The QName must represent the name with respect to the namespace
8729 * declarations in effect on the node whose name is being represented.
8730 * Typically, this will be the form in which the name occurred in the XML
8731 * source. This need not be the case if there are namespace declarations
8732 * in effect on the node that associate multiple prefixes with the same
8733 * namespace. However, an implementation may include information about
8734 * the original prefix in its representation of nodes; in this case, an
8735 * implementation can ensure that the returned string is always the same
8736 * as the QName used in the XML source. If the argument it omitted it
8737 * defaults to the context node.
8738 * Libxml keep the original prefix so the "real qualified name" used is
8739 * returned.
8740 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008741static void
Daniel Veillard04383752001-07-08 14:27:15 +00008742xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8743{
Owen Taylor3473f882001-02-23 17:55:21 +00008744 xmlXPathObjectPtr cur;
8745
8746 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008747 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8748 ctxt->context->node));
Daniel Veillard04383752001-07-08 14:27:15 +00008749 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008750 }
8751
8752 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00008753 if ((ctxt->value == NULL) ||
8754 ((ctxt->value->type != XPATH_NODESET) &&
8755 (ctxt->value->type != XPATH_XSLT_TREE)))
8756 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00008757 cur = valuePop(ctxt);
8758
Daniel Veillard911f49a2001-04-07 15:39:35 +00008759 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008760 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008761 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00008762 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00008763
Daniel Veillard04383752001-07-08 14:27:15 +00008764 switch (cur->nodesetval->nodeTab[i]->type) {
8765 case XML_ELEMENT_NODE:
8766 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008767 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008768 valuePush(ctxt,
8769 xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008770 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8771 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008772 valuePush(ctxt,
8773 xmlXPathCacheNewString(ctxt->context,
8774 cur->nodesetval->nodeTab[i]->name));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008775 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00008776 xmlChar *fullname;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008777
Daniel Veillardc00cda82003-04-07 10:22:39 +00008778 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8779 cur->nodesetval->nodeTab[i]->ns->prefix,
8780 NULL, 0);
8781 if (fullname == cur->nodesetval->nodeTab[i]->name)
8782 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8783 if (fullname == NULL) {
8784 XP_ERROR(XPATH_MEMORY_ERROR);
8785 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008786 valuePush(ctxt, xmlXPathCacheWrapString(
8787 ctxt->context, fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00008788 }
8789 break;
8790 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008791 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8792 cur->nodesetval->nodeTab[i]));
Daniel Veillard04383752001-07-08 14:27:15 +00008793 xmlXPathLocalNameFunction(ctxt, 1);
8794 }
Owen Taylor3473f882001-02-23 17:55:21 +00008795 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008796 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008797}
8798
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008799
8800/**
Owen Taylor3473f882001-02-23 17:55:21 +00008801 * xmlXPathStringFunction:
8802 * @ctxt: the XPath Parser context
8803 * @nargs: the number of arguments
8804 *
8805 * Implement the string() XPath function
8806 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00008807 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00008808 * - A node-set is converted to a string by returning the value of
8809 * the node in the node-set that is first in document order.
8810 * If the node-set is empty, an empty string is returned.
8811 * - A number is converted to a string as follows
Daniel Veillard45490ae2008-07-29 09:13:19 +00008812 * + NaN is converted to the string NaN
8813 * + positive zero is converted to the string 0
8814 * + negative zero is converted to the string 0
8815 * + positive infinity is converted to the string Infinity
8816 * + negative infinity is converted to the string -Infinity
Owen Taylor3473f882001-02-23 17:55:21 +00008817 * + if the number is an integer, the number is represented in
8818 * decimal form as a Number with no decimal point and no leading
8819 * zeros, preceded by a minus sign (-) if the number is negative
8820 * + otherwise, the number is represented in decimal form as a
8821 * Number including a decimal point with at least one digit
8822 * before the decimal point and at least one digit after the
8823 * decimal point, preceded by a minus sign (-) if the number
8824 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008825 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00008826 * before the decimal point; beyond the one required digit
8827 * after the decimal point there must be as many, but only as
8828 * many, more digits as are needed to uniquely distinguish the
8829 * number from all other IEEE 754 numeric values.
8830 * - The boolean false value is converted to the string false.
8831 * The boolean true value is converted to the string true.
8832 *
8833 * If the argument is omitted, it defaults to a node-set with the
8834 * context node as its only member.
8835 */
8836void
8837xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8838 xmlXPathObjectPtr cur;
8839
Daniel Veillarda82b1822004-11-08 16:24:57 +00008840 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008841 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008842 valuePush(ctxt,
8843 xmlXPathCacheWrapString(ctxt->context,
8844 xmlXPathCastNodeToString(ctxt->context->node)));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008845 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008846 }
8847
8848 CHECK_ARITY(1);
8849 cur = valuePop(ctxt);
8850 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008851 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00008852}
8853
8854/**
8855 * xmlXPathStringLengthFunction:
8856 * @ctxt: the XPath Parser context
8857 * @nargs: the number of arguments
8858 *
8859 * Implement the string-length() XPath function
8860 * number string-length(string?)
8861 * The string-length returns the number of characters in the string
8862 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8863 * the context node converted to a string, in other words the value
8864 * of the context node.
8865 */
8866void
8867xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8868 xmlXPathObjectPtr cur;
8869
8870 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008871 if ((ctxt == NULL) || (ctxt->context == NULL))
8872 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008873 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008874 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008875 } else {
8876 xmlChar *content;
8877
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008878 content = xmlXPathCastNodeToString(ctxt->context->node);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008879 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8880 xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00008881 xmlFree(content);
8882 }
8883 return;
8884 }
8885 CHECK_ARITY(1);
8886 CAST_TO_STRING;
8887 CHECK_TYPE(XPATH_STRING);
8888 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008889 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
Daniel Veillard45490ae2008-07-29 09:13:19 +00008890 xmlUTF8Strlen(cur->stringval)));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008891 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008892}
8893
8894/**
8895 * xmlXPathConcatFunction:
8896 * @ctxt: the XPath Parser context
8897 * @nargs: the number of arguments
8898 *
8899 * Implement the concat() XPath function
8900 * string concat(string, string, string*)
8901 * The concat function returns the concatenation of its arguments.
8902 */
8903void
8904xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8905 xmlXPathObjectPtr cur, newobj;
8906 xmlChar *tmp;
8907
Daniel Veillarda82b1822004-11-08 16:24:57 +00008908 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008909 if (nargs < 2) {
8910 CHECK_ARITY(2);
8911 }
8912
8913 CAST_TO_STRING;
8914 cur = valuePop(ctxt);
8915 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008916 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008917 return;
8918 }
8919 nargs--;
8920
8921 while (nargs > 0) {
8922 CAST_TO_STRING;
8923 newobj = valuePop(ctxt);
8924 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008925 xmlXPathReleaseObject(ctxt->context, newobj);
8926 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008927 XP_ERROR(XPATH_INVALID_TYPE);
8928 }
8929 tmp = xmlStrcat(newobj->stringval, cur->stringval);
8930 newobj->stringval = cur->stringval;
8931 cur->stringval = tmp;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008932 xmlXPathReleaseObject(ctxt->context, newobj);
Owen Taylor3473f882001-02-23 17:55:21 +00008933 nargs--;
8934 }
8935 valuePush(ctxt, cur);
8936}
8937
8938/**
8939 * xmlXPathContainsFunction:
8940 * @ctxt: the XPath Parser context
8941 * @nargs: the number of arguments
8942 *
8943 * Implement the contains() XPath function
8944 * boolean contains(string, string)
8945 * The contains function returns true if the first argument string
8946 * contains the second argument string, and otherwise returns false.
8947 */
8948void
8949xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8950 xmlXPathObjectPtr hay, needle;
8951
8952 CHECK_ARITY(2);
8953 CAST_TO_STRING;
8954 CHECK_TYPE(XPATH_STRING);
8955 needle = valuePop(ctxt);
8956 CAST_TO_STRING;
8957 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008958
Owen Taylor3473f882001-02-23 17:55:21 +00008959 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008960 xmlXPathReleaseObject(ctxt->context, hay);
8961 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008962 XP_ERROR(XPATH_INVALID_TYPE);
8963 }
8964 if (xmlStrstr(hay->stringval, needle->stringval))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008965 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00008966 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008967 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8968 xmlXPathReleaseObject(ctxt->context, hay);
8969 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008970}
8971
8972/**
8973 * xmlXPathStartsWithFunction:
8974 * @ctxt: the XPath Parser context
8975 * @nargs: the number of arguments
8976 *
8977 * Implement the starts-with() XPath function
8978 * boolean starts-with(string, string)
8979 * The starts-with function returns true if the first argument string
8980 * starts with the second argument string, and otherwise returns false.
8981 */
8982void
8983xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8984 xmlXPathObjectPtr hay, needle;
8985 int n;
8986
8987 CHECK_ARITY(2);
8988 CAST_TO_STRING;
8989 CHECK_TYPE(XPATH_STRING);
8990 needle = valuePop(ctxt);
8991 CAST_TO_STRING;
8992 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008993
Owen Taylor3473f882001-02-23 17:55:21 +00008994 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008995 xmlXPathReleaseObject(ctxt->context, hay);
8996 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008997 XP_ERROR(XPATH_INVALID_TYPE);
8998 }
8999 n = xmlStrlen(needle->stringval);
9000 if (xmlStrncmp(hay->stringval, needle->stringval, n))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009001 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009002 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009003 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9004 xmlXPathReleaseObject(ctxt->context, hay);
9005 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009006}
9007
9008/**
9009 * xmlXPathSubstringFunction:
9010 * @ctxt: the XPath Parser context
9011 * @nargs: the number of arguments
9012 *
9013 * Implement the substring() XPath function
9014 * string substring(string, number, number?)
9015 * The substring function returns the substring of the first argument
9016 * starting at the position specified in the second argument with
9017 * length specified in the third argument. For example,
9018 * substring("12345",2,3) returns "234". If the third argument is not
9019 * specified, it returns the substring starting at the position specified
9020 * in the second argument and continuing to the end of the string. For
9021 * example, substring("12345",2) returns "2345". More precisely, each
9022 * character in the string (see [3.6 Strings]) is considered to have a
9023 * numeric position: the position of the first character is 1, the position
9024 * of the second character is 2 and so on. The returned substring contains
9025 * those characters for which the position of the character is greater than
9026 * or equal to the second argument and, if the third argument is specified,
9027 * less than the sum of the second and third arguments; the comparisons
9028 * and addition used for the above follow the standard IEEE 754 rules. Thus:
Daniel Veillard45490ae2008-07-29 09:13:19 +00009029 * - substring("12345", 1.5, 2.6) returns "234"
9030 * - substring("12345", 0, 3) returns "12"
9031 * - substring("12345", 0 div 0, 3) returns ""
9032 * - substring("12345", 1, 0 div 0) returns ""
9033 * - substring("12345", -42, 1 div 0) returns "12345"
9034 * - substring("12345", -1 div 0, 1 div 0) returns ""
Owen Taylor3473f882001-02-23 17:55:21 +00009035 */
9036void
9037xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9038 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009039 double le=0, in;
9040 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00009041 xmlChar *ret;
9042
Owen Taylor3473f882001-02-23 17:55:21 +00009043 if (nargs < 2) {
9044 CHECK_ARITY(2);
9045 }
9046 if (nargs > 3) {
9047 CHECK_ARITY(3);
9048 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009049 /*
9050 * take care of possible last (position) argument
9051 */
Owen Taylor3473f882001-02-23 17:55:21 +00009052 if (nargs == 3) {
9053 CAST_TO_NUMBER;
9054 CHECK_TYPE(XPATH_NUMBER);
9055 len = valuePop(ctxt);
9056 le = len->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009057 xmlXPathReleaseObject(ctxt->context, len);
Owen Taylor3473f882001-02-23 17:55:21 +00009058 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009059
Owen Taylor3473f882001-02-23 17:55:21 +00009060 CAST_TO_NUMBER;
9061 CHECK_TYPE(XPATH_NUMBER);
9062 start = valuePop(ctxt);
9063 in = start->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009064 xmlXPathReleaseObject(ctxt->context, start);
Owen Taylor3473f882001-02-23 17:55:21 +00009065 CAST_TO_STRING;
9066 CHECK_TYPE(XPATH_STRING);
9067 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00009068 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00009069
Daniel Veillard97ac1312001-05-30 19:14:17 +00009070 /*
9071 * If last pos not present, calculate last position
9072 */
Daniel Veillard9e412302002-06-10 15:59:44 +00009073 if (nargs != 3) {
9074 le = (double)m;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009075 if (in < 1.0)
Daniel Veillard9e412302002-06-10 15:59:44 +00009076 in = 1.0;
9077 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009078
Daniel Veillard45490ae2008-07-29 09:13:19 +00009079 /* Need to check for the special cases where either
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009080 * the index is NaN, the length is NaN, or both
9081 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00009082 */
Daniel Veillard48b3eb22009-03-25 09:51:19 +00009083 if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009084 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00009085 * To meet the requirements of the spec, the arguments
Daniel Veillard45490ae2008-07-29 09:13:19 +00009086 * must be converted to integer format before
Daniel Veillard9e412302002-06-10 15:59:44 +00009087 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009088 *
Daniel Veillard9e412302002-06-10 15:59:44 +00009089 * First we go to integer form, rounding up
9090 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009091 */
9092 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00009093 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00009094
Daniel Veillard9e412302002-06-10 15:59:44 +00009095 if (xmlXPathIsInf(le) == 1) {
9096 l = m;
9097 if (i < 1)
9098 i = 1;
9099 }
9100 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9101 l = 0;
9102 else {
9103 l = (int) le;
9104 if (((double)l)+0.5 <= le) l++;
9105 }
9106
9107 /* Now we normalize inidices */
9108 i -= 1;
9109 l += i;
9110 if (i < 0)
9111 i = 0;
9112 if (l > m)
9113 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00009114
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009115 /* number of chars to copy */
9116 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00009117
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009118 ret = xmlUTF8Strsub(str->stringval, i, l);
9119 }
9120 else {
9121 ret = NULL;
9122 }
Owen Taylor3473f882001-02-23 17:55:21 +00009123 if (ret == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009124 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00009125 else {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009126 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009127 xmlFree(ret);
9128 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009129 xmlXPathReleaseObject(ctxt->context, str);
Owen Taylor3473f882001-02-23 17:55:21 +00009130}
9131
9132/**
9133 * xmlXPathSubstringBeforeFunction:
9134 * @ctxt: the XPath Parser context
9135 * @nargs: the number of arguments
9136 *
9137 * Implement the substring-before() XPath function
9138 * string substring-before(string, string)
9139 * The substring-before function returns the substring of the first
9140 * argument string that precedes the first occurrence of the second
9141 * argument string in the first argument string, or the empty string
9142 * if the first argument string does not contain the second argument
9143 * string. For example, substring-before("1999/04/01","/") returns 1999.
9144 */
9145void
9146xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9147 xmlXPathObjectPtr str;
9148 xmlXPathObjectPtr find;
9149 xmlBufferPtr target;
9150 const xmlChar *point;
9151 int offset;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009152
Owen Taylor3473f882001-02-23 17:55:21 +00009153 CHECK_ARITY(2);
9154 CAST_TO_STRING;
9155 find = valuePop(ctxt);
9156 CAST_TO_STRING;
9157 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009158
Owen Taylor3473f882001-02-23 17:55:21 +00009159 target = xmlBufferCreate();
9160 if (target) {
9161 point = xmlStrstr(str->stringval, find->stringval);
9162 if (point) {
9163 offset = (int)(point - str->stringval);
9164 xmlBufferAdd(target, str->stringval, offset);
9165 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009166 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9167 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00009168 xmlBufferFree(target);
9169 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009170 xmlXPathReleaseObject(ctxt->context, str);
9171 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009172}
9173
9174/**
9175 * xmlXPathSubstringAfterFunction:
9176 * @ctxt: the XPath Parser context
9177 * @nargs: the number of arguments
9178 *
9179 * Implement the substring-after() XPath function
9180 * string substring-after(string, string)
9181 * The substring-after function returns the substring of the first
9182 * argument string that follows the first occurrence of the second
9183 * argument string in the first argument string, or the empty stringi
9184 * if the first argument string does not contain the second argument
9185 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9186 * and substring-after("1999/04/01","19") returns 99/04/01.
9187 */
9188void
9189xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9190 xmlXPathObjectPtr str;
9191 xmlXPathObjectPtr find;
9192 xmlBufferPtr target;
9193 const xmlChar *point;
9194 int offset;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009195
Owen Taylor3473f882001-02-23 17:55:21 +00009196 CHECK_ARITY(2);
9197 CAST_TO_STRING;
9198 find = valuePop(ctxt);
9199 CAST_TO_STRING;
9200 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009201
Owen Taylor3473f882001-02-23 17:55:21 +00009202 target = xmlBufferCreate();
9203 if (target) {
9204 point = xmlStrstr(str->stringval, find->stringval);
9205 if (point) {
9206 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9207 xmlBufferAdd(target, &str->stringval[offset],
9208 xmlStrlen(str->stringval) - offset);
9209 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009210 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillard45490ae2008-07-29 09:13:19 +00009211 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00009212 xmlBufferFree(target);
9213 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009214 xmlXPathReleaseObject(ctxt->context, str);
9215 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009216}
9217
9218/**
9219 * xmlXPathNormalizeFunction:
9220 * @ctxt: the XPath Parser context
9221 * @nargs: the number of arguments
9222 *
9223 * Implement the normalize-space() XPath function
9224 * string normalize-space(string?)
9225 * The normalize-space function returns the argument string with white
9226 * space normalized by stripping leading and trailing whitespace
9227 * and replacing sequences of whitespace characters by a single
9228 * space. Whitespace characters are the same allowed by the S production
9229 * in XML. If the argument is omitted, it defaults to the context
9230 * node converted to a string, in other words the value of the context node.
9231 */
9232void
9233xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9234 xmlXPathObjectPtr obj = NULL;
9235 xmlChar *source = NULL;
9236 xmlBufferPtr target;
9237 xmlChar blank;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009238
Daniel Veillarda82b1822004-11-08 16:24:57 +00009239 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009240 if (nargs == 0) {
9241 /* Use current context node */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009242 valuePush(ctxt,
9243 xmlXPathCacheWrapString(ctxt->context,
9244 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00009245 nargs = 1;
9246 }
9247
9248 CHECK_ARITY(1);
9249 CAST_TO_STRING;
9250 CHECK_TYPE(XPATH_STRING);
9251 obj = valuePop(ctxt);
9252 source = obj->stringval;
9253
9254 target = xmlBufferCreate();
9255 if (target && source) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00009256
Owen Taylor3473f882001-02-23 17:55:21 +00009257 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00009258 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00009259 source++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009260
Owen Taylor3473f882001-02-23 17:55:21 +00009261 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9262 blank = 0;
9263 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00009264 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009265 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00009266 } else {
9267 if (blank) {
9268 xmlBufferAdd(target, &blank, 1);
9269 blank = 0;
9270 }
9271 xmlBufferAdd(target, source, 1);
9272 }
9273 source++;
9274 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009275 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9276 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00009277 xmlBufferFree(target);
9278 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009279 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00009280}
9281
9282/**
9283 * xmlXPathTranslateFunction:
9284 * @ctxt: the XPath Parser context
9285 * @nargs: the number of arguments
9286 *
9287 * Implement the translate() XPath function
9288 * string translate(string, string, string)
9289 * The translate function returns the first argument string with
9290 * occurrences of characters in the second argument string replaced
9291 * by the character at the corresponding position in the third argument
9292 * string. For example, translate("bar","abc","ABC") returns the string
9293 * BAr. If there is a character in the second argument string with no
9294 * character at a corresponding position in the third argument string
9295 * (because the second argument string is longer than the third argument
9296 * string), then occurrences of that character in the first argument
9297 * string are removed. For example, translate("--aaa--","abc-","ABC")
9298 * returns "AAA". If a character occurs more than once in second
9299 * argument string, then the first occurrence determines the replacement
9300 * character. If the third argument string is longer than the second
9301 * argument string, then excess characters are ignored.
9302 */
9303void
9304xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00009305 xmlXPathObjectPtr str;
9306 xmlXPathObjectPtr from;
9307 xmlXPathObjectPtr to;
9308 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009309 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009310 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00009311 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009312 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00009313
Daniel Veillarde043ee12001-04-16 14:08:07 +00009314 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00009315
Daniel Veillarde043ee12001-04-16 14:08:07 +00009316 CAST_TO_STRING;
9317 to = valuePop(ctxt);
9318 CAST_TO_STRING;
9319 from = valuePop(ctxt);
9320 CAST_TO_STRING;
9321 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009322
Daniel Veillarde043ee12001-04-16 14:08:07 +00009323 target = xmlBufferCreate();
9324 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009325 max = xmlUTF8Strlen(to->stringval);
9326 for (cptr = str->stringval; (ch=*cptr); ) {
9327 offset = xmlUTF8Strloc(from->stringval, cptr);
9328 if (offset >= 0) {
9329 if (offset < max) {
9330 point = xmlUTF8Strpos(to->stringval, offset);
9331 if (point)
9332 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
9333 }
9334 } else
9335 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9336
9337 /* Step to next character in input */
9338 cptr++;
9339 if ( ch & 0x80 ) {
9340 /* if not simple ascii, verify proper format */
9341 if ( (ch & 0xc0) != 0xc0 ) {
9342 xmlGenericError(xmlGenericErrorContext,
9343 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08009344 /* not asserting an XPath error is probably better */
Daniel Veillard97ac1312001-05-30 19:14:17 +00009345 break;
9346 }
9347 /* then skip over remaining bytes for this char */
9348 while ( (ch <<= 1) & 0x80 )
9349 if ( (*cptr++ & 0xc0) != 0x80 ) {
9350 xmlGenericError(xmlGenericErrorContext,
9351 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08009352 /* not asserting an XPath error is probably better */
Daniel Veillard97ac1312001-05-30 19:14:17 +00009353 break;
9354 }
9355 if (ch & 0x80) /* must have had error encountered */
9356 break;
9357 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00009358 }
Owen Taylor3473f882001-02-23 17:55:21 +00009359 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009360 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9361 xmlBufferContent(target)));
Daniel Veillarde043ee12001-04-16 14:08:07 +00009362 xmlBufferFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009363 xmlXPathReleaseObject(ctxt->context, str);
9364 xmlXPathReleaseObject(ctxt->context, from);
9365 xmlXPathReleaseObject(ctxt->context, to);
Owen Taylor3473f882001-02-23 17:55:21 +00009366}
9367
9368/**
9369 * xmlXPathBooleanFunction:
9370 * @ctxt: the XPath Parser context
9371 * @nargs: the number of arguments
9372 *
9373 * Implement the boolean() XPath function
9374 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00009375 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00009376 * - a number is true if and only if it is neither positive or
9377 * negative zero nor NaN
9378 * - a node-set is true if and only if it is non-empty
9379 * - a string is true if and only if its length is non-zero
9380 */
9381void
9382xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9383 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00009384
9385 CHECK_ARITY(1);
9386 cur = valuePop(ctxt);
9387 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009388 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009389 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009390}
9391
9392/**
9393 * xmlXPathNotFunction:
9394 * @ctxt: the XPath Parser context
9395 * @nargs: the number of arguments
9396 *
9397 * Implement the not() XPath function
9398 * boolean not(boolean)
9399 * The not function returns true if its argument is false,
9400 * and false otherwise.
9401 */
9402void
9403xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9404 CHECK_ARITY(1);
9405 CAST_TO_BOOLEAN;
9406 CHECK_TYPE(XPATH_BOOLEAN);
9407 ctxt->value->boolval = ! ctxt->value->boolval;
9408}
9409
9410/**
9411 * xmlXPathTrueFunction:
9412 * @ctxt: the XPath Parser context
9413 * @nargs: the number of arguments
9414 *
9415 * Implement the true() XPath function
9416 * boolean true()
9417 */
9418void
9419xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9420 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009421 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009422}
9423
9424/**
9425 * xmlXPathFalseFunction:
9426 * @ctxt: the XPath Parser context
9427 * @nargs: the number of arguments
9428 *
9429 * Implement the false() XPath function
9430 * boolean false()
9431 */
9432void
9433xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9434 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009435 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009436}
9437
9438/**
9439 * xmlXPathLangFunction:
9440 * @ctxt: the XPath Parser context
9441 * @nargs: the number of arguments
9442 *
9443 * Implement the lang() XPath function
9444 * boolean lang(string)
9445 * The lang function returns true or false depending on whether the
9446 * language of the context node as specified by xml:lang attributes
9447 * is the same as or is a sublanguage of the language specified by
9448 * the argument string. The language of the context node is determined
9449 * by the value of the xml:lang attribute on the context node, or, if
9450 * the context node has no xml:lang attribute, by the value of the
9451 * xml:lang attribute on the nearest ancestor of the context node that
9452 * has an xml:lang attribute. If there is no such attribute, then lang
9453 * returns false. If there is such an attribute, then lang returns
9454 * true if the attribute value is equal to the argument ignoring case,
9455 * or if there is some suffix starting with - such that the attribute
9456 * value is equal to the argument ignoring that suffix of the attribute
9457 * value and ignoring case.
9458 */
9459void
9460xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009461 xmlXPathObjectPtr val = NULL;
9462 const xmlChar *theLang = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009463 const xmlChar *lang;
9464 int ret = 0;
9465 int i;
9466
9467 CHECK_ARITY(1);
9468 CAST_TO_STRING;
9469 CHECK_TYPE(XPATH_STRING);
9470 val = valuePop(ctxt);
9471 lang = val->stringval;
9472 theLang = xmlNodeGetLang(ctxt->context->node);
9473 if ((theLang != NULL) && (lang != NULL)) {
9474 for (i = 0;lang[i] != 0;i++)
9475 if (toupper(lang[i]) != toupper(theLang[i]))
9476 goto not_equal;
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009477 if ((theLang[i] == 0) || (theLang[i] == '-'))
9478 ret = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009479 }
9480not_equal:
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009481 if (theLang != NULL)
9482 xmlFree((void *)theLang);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009483
9484 xmlXPathReleaseObject(ctxt->context, val);
9485 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009486}
9487
9488/**
9489 * xmlXPathNumberFunction:
9490 * @ctxt: the XPath Parser context
9491 * @nargs: the number of arguments
9492 *
9493 * Implement the number() XPath function
9494 * number number(object?)
9495 */
9496void
9497xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9498 xmlXPathObjectPtr cur;
9499 double res;
9500
Daniel Veillarda82b1822004-11-08 16:24:57 +00009501 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009502 if (nargs == 0) {
9503 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009504 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
Owen Taylor3473f882001-02-23 17:55:21 +00009505 } else {
9506 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9507
9508 res = xmlXPathStringEvalNumber(content);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009509 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
Owen Taylor3473f882001-02-23 17:55:21 +00009510 xmlFree(content);
9511 }
9512 return;
9513 }
9514
9515 CHECK_ARITY(1);
9516 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009517 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00009518}
9519
9520/**
9521 * xmlXPathSumFunction:
9522 * @ctxt: the XPath Parser context
9523 * @nargs: the number of arguments
9524 *
9525 * Implement the sum() XPath function
9526 * number sum(node-set)
9527 * The sum function returns the sum of the values of the nodes in
9528 * the argument node-set.
9529 */
9530void
9531xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9532 xmlXPathObjectPtr cur;
9533 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009534 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00009535
9536 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009537 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009538 ((ctxt->value->type != XPATH_NODESET) &&
9539 (ctxt->value->type != XPATH_XSLT_TREE)))
9540 XP_ERROR(XPATH_INVALID_TYPE);
9541 cur = valuePop(ctxt);
9542
William M. Brack08171912003-12-29 02:52:11 +00009543 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009544 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9545 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00009546 }
9547 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009548 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9549 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009550}
9551
William M. Brack3d426662005-04-19 14:40:28 +00009552/*
9553 * To assure working code on multiple platforms, we want to only depend
9554 * upon the characteristic truncation of converting a floating point value
9555 * to an integer. Unfortunately, because of the different storage sizes
9556 * of our internal floating point value (double) and integer (int), we
9557 * can't directly convert (see bug 301162). This macro is a messy
9558 * 'workaround'
9559 */
9560#define XTRUNC(f, v) \
9561 f = fmod((v), INT_MAX); \
9562 f = (v) - (f) + (double)((int)(f));
9563
Owen Taylor3473f882001-02-23 17:55:21 +00009564/**
9565 * xmlXPathFloorFunction:
9566 * @ctxt: the XPath Parser context
9567 * @nargs: the number of arguments
9568 *
9569 * Implement the floor() XPath function
9570 * number floor(number)
9571 * The floor function returns the largest (closest to positive infinity)
9572 * number that is not greater than the argument and that is an integer.
9573 */
9574void
9575xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009576 double f;
9577
Owen Taylor3473f882001-02-23 17:55:21 +00009578 CHECK_ARITY(1);
9579 CAST_TO_NUMBER;
9580 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009581
William M. Brack3d426662005-04-19 14:40:28 +00009582 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009583 if (f != ctxt->value->floatval) {
9584 if (ctxt->value->floatval > 0)
9585 ctxt->value->floatval = f;
9586 else
9587 ctxt->value->floatval = f - 1;
9588 }
Owen Taylor3473f882001-02-23 17:55:21 +00009589}
9590
9591/**
9592 * xmlXPathCeilingFunction:
9593 * @ctxt: the XPath Parser context
9594 * @nargs: the number of arguments
9595 *
9596 * Implement the ceiling() XPath function
9597 * number ceiling(number)
9598 * The ceiling function returns the smallest (closest to negative infinity)
9599 * number that is not less than the argument and that is an integer.
9600 */
9601void
9602xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9603 double f;
9604
9605 CHECK_ARITY(1);
9606 CAST_TO_NUMBER;
9607 CHECK_TYPE(XPATH_NUMBER);
9608
9609#if 0
9610 ctxt->value->floatval = ceil(ctxt->value->floatval);
9611#else
William M. Brack3d426662005-04-19 14:40:28 +00009612 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009613 if (f != ctxt->value->floatval) {
9614 if (ctxt->value->floatval > 0)
9615 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009616 else {
9617 if (ctxt->value->floatval < 0 && f == 0)
9618 ctxt->value->floatval = xmlXPathNZERO;
9619 else
9620 ctxt->value->floatval = f;
9621 }
9622
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009623 }
Owen Taylor3473f882001-02-23 17:55:21 +00009624#endif
9625}
9626
9627/**
9628 * xmlXPathRoundFunction:
9629 * @ctxt: the XPath Parser context
9630 * @nargs: the number of arguments
9631 *
9632 * Implement the round() XPath function
9633 * number round(number)
9634 * The round function returns the number that is closest to the
9635 * argument and that is an integer. If there are two such numbers,
9636 * then the one that is even is returned.
9637 */
9638void
9639xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9640 double f;
9641
9642 CHECK_ARITY(1);
9643 CAST_TO_NUMBER;
9644 CHECK_TYPE(XPATH_NUMBER);
9645
Daniel Veillardcda96922001-08-21 10:56:31 +00009646 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9647 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9648 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009649 (ctxt->value->floatval == 0.0))
9650 return;
9651
William M. Brack3d426662005-04-19 14:40:28 +00009652 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009653 if (ctxt->value->floatval < 0) {
9654 if (ctxt->value->floatval < f - 0.5)
9655 ctxt->value->floatval = f - 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009656 else
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009657 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009658 if (ctxt->value->floatval == 0)
9659 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009660 } else {
9661 if (ctxt->value->floatval < f + 0.5)
9662 ctxt->value->floatval = f;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009663 else
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009664 ctxt->value->floatval = f + 1;
9665 }
Owen Taylor3473f882001-02-23 17:55:21 +00009666}
9667
9668/************************************************************************
9669 * *
9670 * The Parser *
9671 * *
9672 ************************************************************************/
9673
9674/*
William M. Brack08171912003-12-29 02:52:11 +00009675 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00009676 * implementation.
9677 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009678static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009679static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009680static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009681static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00009682static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9683 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00009684
9685/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00009686 * xmlXPathCurrentChar:
9687 * @ctxt: the XPath parser context
9688 * @cur: pointer to the beginning of the char
9689 * @len: pointer to the length of the char read
9690 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009691 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00009692 * bytes in the input buffer.
9693 *
Daniel Veillard60087f32001-10-10 09:45:09 +00009694 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00009695 */
9696
9697static int
9698xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9699 unsigned char c;
9700 unsigned int val;
9701 const xmlChar *cur;
9702
9703 if (ctxt == NULL)
9704 return(0);
9705 cur = ctxt->cur;
9706
9707 /*
9708 * We are supposed to handle UTF8, check it's valid
9709 * From rfc2044: encoding of the Unicode values on UTF-8:
9710 *
9711 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9712 * 0000 0000-0000 007F 0xxxxxxx
9713 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
Daniel Veillard45490ae2008-07-29 09:13:19 +00009714 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
Daniel Veillard61d80a22001-04-27 17:13:01 +00009715 *
9716 * Check for the 0x110000 limit too
9717 */
9718 c = *cur;
9719 if (c & 0x80) {
9720 if ((cur[1] & 0xc0) != 0x80)
9721 goto encoding_error;
9722 if ((c & 0xe0) == 0xe0) {
9723
9724 if ((cur[2] & 0xc0) != 0x80)
9725 goto encoding_error;
9726 if ((c & 0xf0) == 0xf0) {
9727 if (((c & 0xf8) != 0xf0) ||
9728 ((cur[3] & 0xc0) != 0x80))
9729 goto encoding_error;
9730 /* 4-byte code */
9731 *len = 4;
9732 val = (cur[0] & 0x7) << 18;
9733 val |= (cur[1] & 0x3f) << 12;
9734 val |= (cur[2] & 0x3f) << 6;
9735 val |= cur[3] & 0x3f;
9736 } else {
9737 /* 3-byte code */
9738 *len = 3;
9739 val = (cur[0] & 0xf) << 12;
9740 val |= (cur[1] & 0x3f) << 6;
9741 val |= cur[2] & 0x3f;
9742 }
9743 } else {
9744 /* 2-byte code */
9745 *len = 2;
9746 val = (cur[0] & 0x1f) << 6;
9747 val |= cur[1] & 0x3f;
9748 }
9749 if (!IS_CHAR(val)) {
9750 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009751 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00009752 return(val);
9753 } else {
9754 /* 1-byte code */
9755 *len = 1;
9756 return((int) *cur);
9757 }
9758encoding_error:
9759 /*
William M. Brack08171912003-12-29 02:52:11 +00009760 * If we detect an UTF8 error that probably means that the
9761 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00009762 * declaration header. Report the error and switch the encoding
9763 * to ISO-Latin-1 (if you don't like this policy, just declare the
9764 * encoding !)
9765 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00009766 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00009767 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009768}
9769
9770/**
Owen Taylor3473f882001-02-23 17:55:21 +00009771 * xmlXPathParseNCName:
9772 * @ctxt: the XPath Parser context
9773 *
9774 * parse an XML namespace non qualified name.
9775 *
9776 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9777 *
9778 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9779 * CombiningChar | Extender
9780 *
9781 * Returns the namespace name or NULL
9782 */
9783
9784xmlChar *
9785xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00009786 const xmlChar *in;
9787 xmlChar *ret;
9788 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009789
Daniel Veillarda82b1822004-11-08 16:24:57 +00009790 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00009791 /*
9792 * Accelerator for simple ASCII names
9793 */
9794 in = ctxt->cur;
9795 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9796 ((*in >= 0x41) && (*in <= 0x5A)) ||
9797 (*in == '_')) {
9798 in++;
9799 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9800 ((*in >= 0x41) && (*in <= 0x5A)) ||
9801 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00009802 (*in == '_') || (*in == '.') ||
9803 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00009804 in++;
9805 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9806 (*in == '[') || (*in == ']') || (*in == ':') ||
9807 (*in == '@') || (*in == '*')) {
9808 count = in - ctxt->cur;
9809 if (count == 0)
9810 return(NULL);
9811 ret = xmlStrndup(ctxt->cur, count);
9812 ctxt->cur = in;
9813 return(ret);
9814 }
9815 }
9816 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009817}
9818
Daniel Veillard2156a562001-04-28 12:24:34 +00009819
Owen Taylor3473f882001-02-23 17:55:21 +00009820/**
9821 * xmlXPathParseQName:
9822 * @ctxt: the XPath Parser context
Daniel Veillard45490ae2008-07-29 09:13:19 +00009823 * @prefix: a xmlChar **
Owen Taylor3473f882001-02-23 17:55:21 +00009824 *
9825 * parse an XML qualified name
9826 *
9827 * [NS 5] QName ::= (Prefix ':')? LocalPart
9828 *
9829 * [NS 6] Prefix ::= NCName
9830 *
9831 * [NS 7] LocalPart ::= NCName
9832 *
9833 * Returns the function returns the local part, and prefix is updated
9834 * to get the Prefix if any.
9835 */
9836
Daniel Veillard56a4cb82001-03-24 17:00:36 +00009837static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00009838xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9839 xmlChar *ret = NULL;
9840
9841 *prefix = NULL;
9842 ret = xmlXPathParseNCName(ctxt);
Daniel Veillard074f37e2008-09-01 13:38:22 +00009843 if (ret && CUR == ':') {
Owen Taylor3473f882001-02-23 17:55:21 +00009844 *prefix = ret;
9845 NEXT;
9846 ret = xmlXPathParseNCName(ctxt);
9847 }
9848 return(ret);
9849}
9850
9851/**
9852 * xmlXPathParseName:
9853 * @ctxt: the XPath Parser context
9854 *
9855 * parse an XML name
9856 *
9857 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9858 * CombiningChar | Extender
9859 *
9860 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9861 *
9862 * Returns the namespace name or NULL
9863 */
9864
9865xmlChar *
9866xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009867 const xmlChar *in;
9868 xmlChar *ret;
9869 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009870
Daniel Veillarda82b1822004-11-08 16:24:57 +00009871 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009872 /*
9873 * Accelerator for simple ASCII names
9874 */
9875 in = ctxt->cur;
9876 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9877 ((*in >= 0x41) && (*in <= 0x5A)) ||
9878 (*in == '_') || (*in == ':')) {
9879 in++;
9880 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9881 ((*in >= 0x41) && (*in <= 0x5A)) ||
9882 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00009883 (*in == '_') || (*in == '-') ||
9884 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00009885 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00009886 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009887 count = in - ctxt->cur;
9888 ret = xmlStrndup(ctxt->cur, count);
9889 ctxt->cur = in;
9890 return(ret);
9891 }
9892 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009893 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009894}
9895
Daniel Veillard61d80a22001-04-27 17:13:01 +00009896static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00009897xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009898 xmlChar buf[XML_MAX_NAMELEN + 5];
9899 int len = 0, l;
9900 int c;
9901
9902 /*
9903 * Handler for more complex cases
9904 */
9905 c = CUR_CHAR(l);
9906 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00009907 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9908 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00009909 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00009910 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009911 return(NULL);
9912 }
9913
9914 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9915 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9916 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00009917 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009918 (IS_COMBINING(c)) ||
9919 (IS_EXTENDER(c)))) {
9920 COPY_BUF(l,buf,len,c);
9921 NEXTL(l);
9922 c = CUR_CHAR(l);
9923 if (len >= XML_MAX_NAMELEN) {
9924 /*
9925 * Okay someone managed to make a huge name, so he's ready to pay
9926 * for the processing speed.
9927 */
9928 xmlChar *buffer;
9929 int max = len * 2;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009930
Daniel Veillard3c908dc2003-04-19 00:07:51 +00009931 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009932 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009933 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009934 }
9935 memcpy(buffer, buf, len);
9936 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9937 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00009938 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009939 (IS_COMBINING(c)) ||
9940 (IS_EXTENDER(c))) {
9941 if (len + 10 > max) {
9942 max *= 2;
9943 buffer = (xmlChar *) xmlRealloc(buffer,
9944 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009945 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009946 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009947 }
9948 }
9949 COPY_BUF(l,buffer,len,c);
9950 NEXTL(l);
9951 c = CUR_CHAR(l);
9952 }
9953 buffer[len] = 0;
9954 return(buffer);
9955 }
9956 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009957 if (len == 0)
9958 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009959 return(xmlStrndup(buf, len));
9960}
Daniel Veillard3cd72402002-05-13 10:33:30 +00009961
9962#define MAX_FRAC 20
9963
William M. Brack372a4452004-02-17 13:09:23 +00009964/*
9965 * These are used as divisors for the fractional part of a number.
9966 * Since the table includes 1.0 (representing '0' fractional digits),
9967 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
9968 */
9969static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +00009970 1.0, 10.0, 100.0, 1000.0, 10000.0,
9971 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
9972 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
9973 100000000000000.0,
9974 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +00009975 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +00009976};
9977
Owen Taylor3473f882001-02-23 17:55:21 +00009978/**
9979 * xmlXPathStringEvalNumber:
9980 * @str: A string to scan
9981 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00009982 * [30a] Float ::= Number ('e' Digits?)?
9983 *
Owen Taylor3473f882001-02-23 17:55:21 +00009984 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard45490ae2008-07-29 09:13:19 +00009985 * | '.' Digits
Owen Taylor3473f882001-02-23 17:55:21 +00009986 * [31] Digits ::= [0-9]+
9987 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009988 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00009989 * In complement of the Number expression, this function also handles
9990 * negative values : '-' Number.
9991 *
9992 * Returns the double value.
9993 */
9994double
9995xmlXPathStringEvalNumber(const xmlChar *str) {
9996 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00009997 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009998 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009999 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010000 int exponent = 0;
10001 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010002#ifdef __GNUC__
10003 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010004 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010005#endif
Daniel Veillardeca82812002-04-24 11:42:02 +000010006 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +000010007 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010008 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
10009 return(xmlXPathNAN);
10010 }
10011 if (*cur == '-') {
10012 isneg = 1;
10013 cur++;
10014 }
Daniel Veillardb06c6142001-08-27 14:26:30 +000010015
10016#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010017 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010018 * tmp/temp is a workaround against a gcc compiler bug
10019 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010020 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010021 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010022 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010023 ret = ret * 10;
10024 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +000010025 ok = 1;
10026 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +000010027 temp = (double) tmp;
10028 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010029 }
Daniel Veillardb06c6142001-08-27 14:26:30 +000010030#else
Daniel Veillard7b416132002-03-07 08:36:03 +000010031 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010032 while ((*cur >= '0') && (*cur <= '9')) {
10033 ret = ret * 10 + (*cur - '0');
10034 ok = 1;
10035 cur++;
10036 }
10037#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010038
Owen Taylor3473f882001-02-23 17:55:21 +000010039 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +000010040 int v, frac = 0;
10041 double fraction = 0;
10042
Owen Taylor3473f882001-02-23 17:55:21 +000010043 cur++;
10044 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10045 return(xmlXPathNAN);
10046 }
Daniel Veillard3cd72402002-05-13 10:33:30 +000010047 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
10048 v = (*cur - '0');
10049 fraction = fraction * 10 + v;
10050 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010051 cur++;
10052 }
Daniel Veillard3cd72402002-05-13 10:33:30 +000010053 fraction /= my_pow10[frac];
10054 ret = ret + fraction;
10055 while ((*cur >= '0') && (*cur <= '9'))
10056 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010057 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010058 if ((*cur == 'e') || (*cur == 'E')) {
10059 cur++;
10060 if (*cur == '-') {
10061 is_exponent_negative = 1;
10062 cur++;
William M. Brack99127052004-05-24 02:52:28 +000010063 } else if (*cur == '+') {
10064 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010065 }
10066 while ((*cur >= '0') && (*cur <= '9')) {
10067 exponent = exponent * 10 + (*cur - '0');
10068 cur++;
10069 }
10070 }
William M. Brack76e95df2003-10-18 16:20:14 +000010071 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010072 if (*cur != 0) return(xmlXPathNAN);
10073 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010074 if (is_exponent_negative) exponent = -exponent;
10075 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +000010076 return(ret);
10077}
10078
10079/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010080 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +000010081 * @ctxt: the XPath Parser context
10082 *
10083 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard45490ae2008-07-29 09:13:19 +000010084 * | '.' Digits
Owen Taylor3473f882001-02-23 17:55:21 +000010085 * [31] Digits ::= [0-9]+
10086 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010087 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +000010088 *
10089 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010090static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010091xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10092{
Owen Taylor3473f882001-02-23 17:55:21 +000010093 double ret = 0.0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010094 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010095 int exponent = 0;
10096 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010097#ifdef __GNUC__
10098 unsigned long tmp = 0;
10099 double temp;
10100#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010101
10102 CHECK_ERROR;
10103 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10104 XP_ERROR(XPATH_NUMBER_ERROR);
10105 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010106#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010107 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010108 * tmp/temp is a workaround against a gcc compiler bug
10109 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010110 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010111 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010112 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010113 ret = ret * 10;
10114 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010115 ok = 1;
10116 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +000010117 temp = (double) tmp;
10118 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010119 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010120#else
10121 ret = 0;
10122 while ((CUR >= '0') && (CUR <= '9')) {
10123 ret = ret * 10 + (CUR - '0');
10124 ok = 1;
10125 NEXT;
10126 }
10127#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010128 if (CUR == '.') {
Phil Shaferee32ad32010-11-03 20:53:55 +010010129 int v, frac = 0;
10130 double fraction = 0;
10131
Owen Taylor3473f882001-02-23 17:55:21 +000010132 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010133 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10134 XP_ERROR(XPATH_NUMBER_ERROR);
10135 }
Phil Shaferee32ad32010-11-03 20:53:55 +010010136 while ((CUR >= '0') && (CUR <= '9') && (frac < MAX_FRAC)) {
10137 v = (CUR - '0');
10138 fraction = fraction * 10 + v;
10139 frac = frac + 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010140 NEXT;
10141 }
Phil Shaferee32ad32010-11-03 20:53:55 +010010142 fraction /= my_pow10[frac];
10143 ret = ret + fraction;
10144 while ((CUR >= '0') && (CUR <= '9'))
10145 NEXT;
Owen Taylor3473f882001-02-23 17:55:21 +000010146 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010147 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010148 NEXT;
10149 if (CUR == '-') {
10150 is_exponent_negative = 1;
10151 NEXT;
William M. Brack99127052004-05-24 02:52:28 +000010152 } else if (CUR == '+') {
10153 NEXT;
10154 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010155 while ((CUR >= '0') && (CUR <= '9')) {
10156 exponent = exponent * 10 + (CUR - '0');
10157 NEXT;
10158 }
10159 if (is_exponent_negative)
10160 exponent = -exponent;
10161 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +000010162 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010163 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010164 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010165}
10166
10167/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010168 * xmlXPathParseLiteral:
10169 * @ctxt: the XPath Parser context
10170 *
10171 * Parse a Literal
10172 *
10173 * [29] Literal ::= '"' [^"]* '"'
10174 * | "'" [^']* "'"
10175 *
10176 * Returns the value found or NULL in case of error
10177 */
10178static xmlChar *
10179xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10180 const xmlChar *q;
10181 xmlChar *ret = NULL;
10182
10183 if (CUR == '"') {
10184 NEXT;
10185 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010186 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010187 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010188 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010189 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010190 } else {
10191 ret = xmlStrndup(q, CUR_PTR - q);
10192 NEXT;
10193 }
10194 } else if (CUR == '\'') {
10195 NEXT;
10196 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010197 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010198 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010199 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010200 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010201 } else {
10202 ret = xmlStrndup(q, CUR_PTR - q);
10203 NEXT;
10204 }
10205 } else {
Daniel Veillard24505b02005-07-28 23:49:35 +000010206 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010207 }
10208 return(ret);
10209}
10210
10211/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010212 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +000010213 * @ctxt: the XPath Parser context
10214 *
10215 * Parse a Literal and push it on the stack.
10216 *
10217 * [29] Literal ::= '"' [^"]* '"'
10218 * | "'" [^']* "'"
10219 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010220 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +000010221 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010222static void
10223xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010224 const xmlChar *q;
10225 xmlChar *ret = NULL;
10226
10227 if (CUR == '"') {
10228 NEXT;
10229 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010230 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +000010231 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010232 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010233 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10234 } else {
10235 ret = xmlStrndup(q, CUR_PTR - q);
10236 NEXT;
10237 }
10238 } else if (CUR == '\'') {
10239 NEXT;
10240 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010241 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +000010242 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010243 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010244 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10245 } else {
10246 ret = xmlStrndup(q, CUR_PTR - q);
10247 NEXT;
10248 }
10249 } else {
10250 XP_ERROR(XPATH_START_LITERAL_ERROR);
10251 }
10252 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010253 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010254 xmlXPathCacheNewString(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010255 xmlFree(ret);
10256}
10257
10258/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010259 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +000010260 * @ctxt: the XPath Parser context
10261 *
10262 * Parse a VariableReference, evaluate it and push it on the stack.
10263 *
10264 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +000010265 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +000010266 * of any of the types that are possible for the value of an expression,
10267 * and may also be of additional types not specified here.
10268 *
10269 * Early evaluation is possible since:
10270 * The variable bindings [...] used to evaluate a subexpression are
Daniel Veillard45490ae2008-07-29 09:13:19 +000010271 * always the same as those used to evaluate the containing expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010272 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010273 * [36] VariableReference ::= '$' QName
Owen Taylor3473f882001-02-23 17:55:21 +000010274 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010275static void
10276xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010277 xmlChar *name;
10278 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010279
10280 SKIP_BLANKS;
10281 if (CUR != '$') {
10282 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10283 }
10284 NEXT;
10285 name = xmlXPathParseQName(ctxt, &prefix);
10286 if (name == NULL) {
10287 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10288 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010289 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010290 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10291 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010292 SKIP_BLANKS;
Daniel Veillardb3d14912005-09-04 20:47:39 +000010293 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10294 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
10295 }
Owen Taylor3473f882001-02-23 17:55:21 +000010296}
10297
10298/**
10299 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +000010300 * @name: a name string
10301 *
10302 * Is the name given a NodeType one.
10303 *
10304 * [38] NodeType ::= 'comment'
10305 * | 'text'
10306 * | 'processing-instruction'
10307 * | 'node'
10308 *
10309 * Returns 1 if true 0 otherwise
10310 */
10311int
10312xmlXPathIsNodeType(const xmlChar *name) {
10313 if (name == NULL)
10314 return(0);
10315
Daniel Veillard1971ee22002-01-31 20:29:19 +000010316 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +000010317 return(1);
10318 if (xmlStrEqual(name, BAD_CAST "text"))
10319 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010320 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +000010321 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010322 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +000010323 return(1);
10324 return(0);
10325}
10326
10327/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010328 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +000010329 * @ctxt: the XPath Parser context
10330 *
10331 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010332 * [17] Argument ::= Expr
Owen Taylor3473f882001-02-23 17:55:21 +000010333 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010334 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +000010335 * pushed on the stack
10336 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010337static void
10338xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010339 xmlChar *name;
10340 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010341 int nbargs = 0;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010342 int sort = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010343
10344 name = xmlXPathParseQName(ctxt, &prefix);
10345 if (name == NULL) {
Daniel Veillard074f37e2008-09-01 13:38:22 +000010346 xmlFree(prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010347 XP_ERROR(XPATH_EXPR_ERROR);
10348 }
10349 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010350#ifdef DEBUG_EXPR
10351 if (prefix == NULL)
10352 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10353 name);
10354 else
10355 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10356 prefix, name);
10357#endif
10358
Owen Taylor3473f882001-02-23 17:55:21 +000010359 if (CUR != '(') {
10360 XP_ERROR(XPATH_EXPR_ERROR);
10361 }
10362 NEXT;
10363 SKIP_BLANKS;
10364
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010365 /*
10366 * Optimization for count(): we don't need the node-set to be sorted.
10367 */
10368 if ((prefix == NULL) && (name[0] == 'c') &&
10369 xmlStrEqual(name, BAD_CAST "count"))
10370 {
10371 sort = 0;
10372 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010373 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +000010374 if (CUR != ')') {
10375 while (CUR != 0) {
10376 int op1 = ctxt->comp->last;
10377 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010378 xmlXPathCompileExpr(ctxt, sort);
Daniel Veillard074f37e2008-09-01 13:38:22 +000010379 if (ctxt->error != XPATH_EXPRESSION_OK) {
10380 xmlFree(name);
10381 xmlFree(prefix);
10382 return;
10383 }
Daniel Veillard71f9d732003-01-14 16:07:16 +000010384 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10385 nbargs++;
10386 if (CUR == ')') break;
10387 if (CUR != ',') {
10388 XP_ERROR(XPATH_EXPR_ERROR);
10389 }
10390 NEXT;
10391 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010392 }
Owen Taylor3473f882001-02-23 17:55:21 +000010393 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010394 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10395 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010396 NEXT;
10397 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010398}
10399
10400/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010401 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010402 * @ctxt: the XPath Parser context
10403 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010404 * [15] PrimaryExpr ::= VariableReference
Owen Taylor3473f882001-02-23 17:55:21 +000010405 * | '(' Expr ')'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010406 * | Literal
10407 * | Number
10408 * | FunctionCall
Owen Taylor3473f882001-02-23 17:55:21 +000010409 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010410 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010411 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010412static void
10413xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010414 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010415 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010416 else if (CUR == '(') {
10417 NEXT;
10418 SKIP_BLANKS;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010419 xmlXPathCompileExpr(ctxt, 1);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010420 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000010421 if (CUR != ')') {
10422 XP_ERROR(XPATH_EXPR_ERROR);
10423 }
10424 NEXT;
10425 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010426 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010427 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010428 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010429 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010430 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010431 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010432 }
10433 SKIP_BLANKS;
10434}
10435
10436/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010437 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010438 * @ctxt: the XPath Parser context
10439 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010440 * [20] FilterExpr ::= PrimaryExpr
10441 * | FilterExpr Predicate
Owen Taylor3473f882001-02-23 17:55:21 +000010442 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010443 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010444 * Square brackets are used to filter expressions in the same way that
10445 * they are used in location paths. It is an error if the expression to
10446 * be filtered does not evaluate to a node-set. The context node list
10447 * used for evaluating the expression in square brackets is the node-set
10448 * to be filtered listed in document order.
10449 */
10450
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010451static void
10452xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10453 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010454 CHECK_ERROR;
10455 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010456
Owen Taylor3473f882001-02-23 17:55:21 +000010457 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010458 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +000010459 SKIP_BLANKS;
10460 }
10461
Daniel Veillard45490ae2008-07-29 09:13:19 +000010462
Owen Taylor3473f882001-02-23 17:55:21 +000010463}
10464
10465/**
10466 * xmlXPathScanName:
10467 * @ctxt: the XPath Parser context
10468 *
10469 * Trickery: parse an XML name but without consuming the input flow
10470 * Needed to avoid insanity in the parser state.
10471 *
10472 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10473 * CombiningChar | Extender
10474 *
10475 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10476 *
10477 * [6] Names ::= Name (S Name)*
10478 *
10479 * Returns the Name parsed or NULL
10480 */
10481
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010482static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +000010483xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +000010484 int len = 0, l;
10485 int c;
Daniel Veillard03226812004-11-01 14:55:21 +000010486 const xmlChar *cur;
10487 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +000010488
Daniel Veillard03226812004-11-01 14:55:21 +000010489 cur = ctxt->cur;
10490
10491 c = CUR_CHAR(l);
10492 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10493 (!IS_LETTER(c) && (c != '_') &&
10494 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010495 return(NULL);
10496 }
10497
Daniel Veillard03226812004-11-01 14:55:21 +000010498 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10499 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10500 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000010501 (c == '_') || (c == ':') ||
Daniel Veillard03226812004-11-01 14:55:21 +000010502 (IS_COMBINING(c)) ||
10503 (IS_EXTENDER(c)))) {
10504 len += l;
10505 NEXTL(l);
10506 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +000010507 }
Daniel Veillard03226812004-11-01 14:55:21 +000010508 ret = xmlStrndup(cur, ctxt->cur - cur);
10509 ctxt->cur = cur;
10510 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +000010511}
10512
10513/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010514 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010515 * @ctxt: the XPath Parser context
10516 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010517 * [19] PathExpr ::= LocationPath
10518 * | FilterExpr
10519 * | FilterExpr '/' RelativeLocationPath
10520 * | FilterExpr '//' RelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000010521 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010522 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010523 * The / operator and // operators combine an arbitrary expression
10524 * and a relative location path. It is an error if the expression
10525 * does not evaluate to a node-set.
10526 * The / operator does composition in the same way as when / is
10527 * used in a location path. As in location paths, // is short for
10528 * /descendant-or-self::node()/.
10529 */
10530
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010531static void
10532xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010533 int lc = 1; /* Should we branch to LocationPath ? */
10534 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10535
10536 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010537 if ((CUR == '$') || (CUR == '(') ||
10538 (IS_ASCII_DIGIT(CUR)) ||
William M. Brackd1757ab2004-10-02 22:07:48 +000010539 (CUR == '\'') || (CUR == '"') ||
10540 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010541 lc = 0;
10542 } else if (CUR == '*') {
10543 /* relative or absolute location path */
10544 lc = 1;
10545 } else if (CUR == '/') {
10546 /* relative or absolute location path */
10547 lc = 1;
10548 } else if (CUR == '@') {
10549 /* relative abbreviated attribute location path */
10550 lc = 1;
10551 } else if (CUR == '.') {
10552 /* relative abbreviated attribute location path */
10553 lc = 1;
10554 } else {
10555 /*
10556 * Problem is finding if we have a name here whether it's:
10557 * - a nodetype
10558 * - a function call in which case it's followed by '('
10559 * - an axis in which case it's followed by ':'
10560 * - a element name
10561 * We do an a priori analysis here rather than having to
10562 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +000010563 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +000010564 * read/write/debug.
10565 */
10566 SKIP_BLANKS;
10567 name = xmlXPathScanName(ctxt);
10568 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10569#ifdef DEBUG_STEP
10570 xmlGenericError(xmlGenericErrorContext,
10571 "PathExpr: Axis\n");
10572#endif
10573 lc = 1;
10574 xmlFree(name);
10575 } else if (name != NULL) {
10576 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +000010577
Daniel Veillard45490ae2008-07-29 09:13:19 +000010578
Owen Taylor3473f882001-02-23 17:55:21 +000010579 while (NXT(len) != 0) {
10580 if (NXT(len) == '/') {
10581 /* element name */
10582#ifdef DEBUG_STEP
10583 xmlGenericError(xmlGenericErrorContext,
10584 "PathExpr: AbbrRelLocation\n");
10585#endif
10586 lc = 1;
10587 break;
William M. Brack76e95df2003-10-18 16:20:14 +000010588 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +000010589 /* ignore blanks */
10590 ;
Owen Taylor3473f882001-02-23 17:55:21 +000010591 } else if (NXT(len) == ':') {
10592#ifdef DEBUG_STEP
10593 xmlGenericError(xmlGenericErrorContext,
10594 "PathExpr: AbbrRelLocation\n");
10595#endif
10596 lc = 1;
10597 break;
10598 } else if ((NXT(len) == '(')) {
10599 /* Note Type or Function */
10600 if (xmlXPathIsNodeType(name)) {
10601#ifdef DEBUG_STEP
10602 xmlGenericError(xmlGenericErrorContext,
10603 "PathExpr: Type search\n");
10604#endif
10605 lc = 1;
10606 } else {
10607#ifdef DEBUG_STEP
10608 xmlGenericError(xmlGenericErrorContext,
10609 "PathExpr: function call\n");
10610#endif
10611 lc = 0;
10612 }
10613 break;
10614 } else if ((NXT(len) == '[')) {
10615 /* element name */
10616#ifdef DEBUG_STEP
10617 xmlGenericError(xmlGenericErrorContext,
10618 "PathExpr: AbbrRelLocation\n");
10619#endif
10620 lc = 1;
10621 break;
10622 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10623 (NXT(len) == '=')) {
10624 lc = 1;
10625 break;
10626 } else {
10627 lc = 1;
10628 break;
10629 }
10630 len++;
10631 }
10632 if (NXT(len) == 0) {
10633#ifdef DEBUG_STEP
10634 xmlGenericError(xmlGenericErrorContext,
10635 "PathExpr: AbbrRelLocation\n");
10636#endif
10637 /* element name */
10638 lc = 1;
10639 }
10640 xmlFree(name);
10641 } else {
William M. Brack08171912003-12-29 02:52:11 +000010642 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +000010643 XP_ERROR(XPATH_EXPR_ERROR);
10644 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000010645 }
Owen Taylor3473f882001-02-23 17:55:21 +000010646
10647 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010648 if (CUR == '/') {
10649 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10650 } else {
10651 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010652 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010653 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010654 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010655 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010656 CHECK_ERROR;
10657 if ((CUR == '/') && (NXT(1) == '/')) {
10658 SKIP(2);
10659 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010660
10661 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10662 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10663 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10664
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010665 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010666 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010667 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010668 }
10669 }
10670 SKIP_BLANKS;
10671}
10672
10673/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010674 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010675 * @ctxt: the XPath Parser context
10676 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010677 * [18] UnionExpr ::= PathExpr
10678 * | UnionExpr '|' PathExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010679 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010680 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010681 */
10682
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010683static void
10684xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10685 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010686 CHECK_ERROR;
10687 SKIP_BLANKS;
10688 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010689 int op1 = ctxt->comp->last;
10690 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010691
10692 NEXT;
10693 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010694 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010695
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010696 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10697
Owen Taylor3473f882001-02-23 17:55:21 +000010698 SKIP_BLANKS;
10699 }
Owen Taylor3473f882001-02-23 17:55:21 +000010700}
10701
10702/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010703 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010704 * @ctxt: the XPath Parser context
10705 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010706 * [27] UnaryExpr ::= UnionExpr
10707 * | '-' UnaryExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010708 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010709 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010710 */
10711
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010712static void
10713xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010714 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010715 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010716
10717 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +000010718 while (CUR == '-') {
10719 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010720 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010721 NEXT;
10722 SKIP_BLANKS;
10723 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010724
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010725 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010726 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010727 if (found) {
10728 if (minus)
10729 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10730 else
10731 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010732 }
10733}
10734
10735/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010736 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010737 * @ctxt: the XPath Parser context
10738 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010739 * [26] MultiplicativeExpr ::= UnaryExpr
10740 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10741 * | MultiplicativeExpr 'div' UnaryExpr
10742 * | MultiplicativeExpr 'mod' UnaryExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010743 * [34] MultiplyOperator ::= '*'
10744 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010745 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010746 */
10747
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010748static void
10749xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10750 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010751 CHECK_ERROR;
10752 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010753 while ((CUR == '*') ||
Owen Taylor3473f882001-02-23 17:55:21 +000010754 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10755 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10756 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010757 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010758
10759 if (CUR == '*') {
10760 op = 0;
10761 NEXT;
10762 } else if (CUR == 'd') {
10763 op = 1;
10764 SKIP(3);
10765 } else if (CUR == 'm') {
10766 op = 2;
10767 SKIP(3);
10768 }
10769 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010770 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010771 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010772 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010773 SKIP_BLANKS;
10774 }
10775}
10776
10777/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010778 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010779 * @ctxt: the XPath Parser context
10780 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010781 * [25] AdditiveExpr ::= MultiplicativeExpr
10782 * | AdditiveExpr '+' MultiplicativeExpr
10783 * | AdditiveExpr '-' MultiplicativeExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010784 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010785 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010786 */
10787
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010788static void
10789xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010790
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010791 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010792 CHECK_ERROR;
10793 SKIP_BLANKS;
10794 while ((CUR == '+') || (CUR == '-')) {
10795 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010796 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010797
10798 if (CUR == '+') plus = 1;
10799 else plus = 0;
10800 NEXT;
10801 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010802 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010803 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010804 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010805 SKIP_BLANKS;
10806 }
10807}
10808
10809/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010810 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010811 * @ctxt: the XPath Parser context
10812 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010813 * [24] RelationalExpr ::= AdditiveExpr
10814 * | RelationalExpr '<' AdditiveExpr
10815 * | RelationalExpr '>' AdditiveExpr
10816 * | RelationalExpr '<=' AdditiveExpr
10817 * | RelationalExpr '>=' AdditiveExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010818 *
10819 * A <= B > C is allowed ? Answer from James, yes with
10820 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10821 * which is basically what got implemented.
10822 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010823 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +000010824 * on the stack
10825 */
10826
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010827static void
10828xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10829 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010830 CHECK_ERROR;
10831 SKIP_BLANKS;
10832 while ((CUR == '<') ||
10833 (CUR == '>') ||
10834 ((CUR == '<') && (NXT(1) == '=')) ||
10835 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010836 int inf, strict;
10837 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010838
10839 if (CUR == '<') inf = 1;
10840 else inf = 0;
10841 if (NXT(1) == '=') strict = 0;
10842 else strict = 1;
10843 NEXT;
10844 if (!strict) NEXT;
10845 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010846 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010847 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010848 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +000010849 SKIP_BLANKS;
10850 }
10851}
10852
10853/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010854 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010855 * @ctxt: the XPath Parser context
10856 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010857 * [23] EqualityExpr ::= RelationalExpr
10858 * | EqualityExpr '=' RelationalExpr
10859 * | EqualityExpr '!=' RelationalExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010860 *
10861 * A != B != C is allowed ? Answer from James, yes with
10862 * (RelationalExpr = RelationalExpr) = RelationalExpr
10863 * (RelationalExpr != RelationalExpr) != RelationalExpr
10864 * which is basically what got implemented.
10865 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010866 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010867 *
10868 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010869static void
10870xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10871 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010872 CHECK_ERROR;
10873 SKIP_BLANKS;
10874 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010875 int eq;
10876 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010877
10878 if (CUR == '=') eq = 1;
10879 else eq = 0;
10880 NEXT;
10881 if (!eq) NEXT;
10882 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010883 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010884 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010885 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010886 SKIP_BLANKS;
10887 }
10888}
10889
10890/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010891 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010892 * @ctxt: the XPath Parser context
10893 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010894 * [22] AndExpr ::= EqualityExpr
10895 * | AndExpr 'and' EqualityExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010896 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010897 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010898 *
10899 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010900static void
10901xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10902 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010903 CHECK_ERROR;
10904 SKIP_BLANKS;
10905 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010906 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010907 SKIP(3);
10908 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010909 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010910 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010911 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010912 SKIP_BLANKS;
10913 }
10914}
10915
10916/**
Daniel Veillard591b4be2003-02-09 23:33:36 +000010917 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010918 * @ctxt: the XPath Parser context
10919 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010920 * [14] Expr ::= OrExpr
10921 * [21] OrExpr ::= AndExpr
10922 * | OrExpr 'or' AndExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010923 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010924 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +000010925 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010926static void
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010927xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010928 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010929 CHECK_ERROR;
10930 SKIP_BLANKS;
10931 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010932 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010933 SKIP(2);
10934 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010935 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010936 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010937 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010938 SKIP_BLANKS;
10939 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010940 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010941 /* more ops could be optimized too */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010942 /*
10943 * This is the main place to eliminate sorting for
10944 * operations which don't require a sorted node-set.
10945 * E.g. count().
10946 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010947 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10948 }
Owen Taylor3473f882001-02-23 17:55:21 +000010949}
10950
10951/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010952 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +000010953 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010954 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +000010955 *
10956 * [8] Predicate ::= '[' PredicateExpr ']'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010957 * [9] PredicateExpr ::= Expr
Owen Taylor3473f882001-02-23 17:55:21 +000010958 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010959 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +000010960 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010961static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010962xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010963 int op1 = ctxt->comp->last;
10964
10965 SKIP_BLANKS;
10966 if (CUR != '[') {
10967 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10968 }
10969 NEXT;
10970 SKIP_BLANKS;
10971
10972 ctxt->comp->last = -1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000010973 /*
10974 * This call to xmlXPathCompileExpr() will deactivate sorting
10975 * of the predicate result.
10976 * TODO: Sorting is still activated for filters, since I'm not
10977 * sure if needed. Normally sorting should not be needed, since
10978 * a filter can only diminish the number of items in a sequence,
10979 * but won't change its order; so if the initial sequence is sorted,
10980 * subsequent sorting is not needed.
10981 */
10982 if (! filter)
10983 xmlXPathCompileExpr(ctxt, 0);
10984 else
10985 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010986 CHECK_ERROR;
10987
10988 if (CUR != ']') {
10989 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10990 }
10991
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010992 if (filter)
10993 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10994 else
10995 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010996
10997 NEXT;
10998 SKIP_BLANKS;
10999}
11000
11001/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011002 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +000011003 * @ctxt: the XPath Parser context
11004 * @test: pointer to a xmlXPathTestVal
11005 * @type: pointer to a xmlXPathTypeVal
11006 * @prefix: placeholder for a possible name prefix
11007 *
11008 * [7] NodeTest ::= NameTest
11009 * | NodeType '(' ')'
11010 * | 'processing-instruction' '(' Literal ')'
11011 *
11012 * [37] NameTest ::= '*'
11013 * | NCName ':' '*'
11014 * | QName
11015 * [38] NodeType ::= 'comment'
11016 * | 'text'
11017 * | 'processing-instruction'
11018 * | 'node'
11019 *
William M. Brack08171912003-12-29 02:52:11 +000011020 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +000011021 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011022static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011023xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11024 xmlXPathTypeVal *type, const xmlChar **prefix,
11025 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +000011026 int blanks;
11027
11028 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11029 STRANGE;
11030 return(NULL);
11031 }
William M. Brack78637da2003-07-31 14:47:38 +000011032 *type = (xmlXPathTypeVal) 0;
11033 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011034 *prefix = NULL;
11035 SKIP_BLANKS;
11036
11037 if ((name == NULL) && (CUR == '*')) {
11038 /*
11039 * All elements
11040 */
11041 NEXT;
11042 *test = NODE_TEST_ALL;
11043 return(NULL);
11044 }
11045
11046 if (name == NULL)
11047 name = xmlXPathParseNCName(ctxt);
11048 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011049 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011050 }
11051
William M. Brack76e95df2003-10-18 16:20:14 +000011052 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +000011053 SKIP_BLANKS;
11054 if (CUR == '(') {
11055 NEXT;
11056 /*
11057 * NodeType or PI search
11058 */
11059 if (xmlStrEqual(name, BAD_CAST "comment"))
11060 *type = NODE_TYPE_COMMENT;
11061 else if (xmlStrEqual(name, BAD_CAST "node"))
11062 *type = NODE_TYPE_NODE;
11063 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11064 *type = NODE_TYPE_PI;
11065 else if (xmlStrEqual(name, BAD_CAST "text"))
11066 *type = NODE_TYPE_TEXT;
11067 else {
11068 if (name != NULL)
11069 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000011070 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011071 }
11072
11073 *test = NODE_TEST_TYPE;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011074
Owen Taylor3473f882001-02-23 17:55:21 +000011075 SKIP_BLANKS;
11076 if (*type == NODE_TYPE_PI) {
11077 /*
11078 * Specific case: search a PI by name.
11079 */
Owen Taylor3473f882001-02-23 17:55:21 +000011080 if (name != NULL)
11081 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +000011082 name = NULL;
11083 if (CUR != ')') {
11084 name = xmlXPathParseLiteral(ctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000011085 CHECK_ERROR NULL;
Daniel Veillarded23b7d2002-05-27 12:16:02 +000011086 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +000011087 SKIP_BLANKS;
11088 }
Owen Taylor3473f882001-02-23 17:55:21 +000011089 }
11090 if (CUR != ')') {
11091 if (name != NULL)
11092 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000011093 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011094 }
11095 NEXT;
11096 return(name);
11097 }
11098 *test = NODE_TEST_NAME;
11099 if ((!blanks) && (CUR == ':')) {
11100 NEXT;
11101
11102 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011103 * Since currently the parser context don't have a
11104 * namespace list associated:
11105 * The namespace name for this prefix can be computed
11106 * only at evaluation time. The compilation is done
11107 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +000011108 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011109#if 0
Owen Taylor3473f882001-02-23 17:55:21 +000011110 *prefix = xmlXPathNsLookup(ctxt->context, name);
11111 if (name != NULL)
11112 xmlFree(name);
11113 if (*prefix == NULL) {
11114 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11115 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011116#else
11117 *prefix = name;
11118#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011119
11120 if (CUR == '*') {
11121 /*
11122 * All elements
11123 */
11124 NEXT;
11125 *test = NODE_TEST_ALL;
11126 return(NULL);
11127 }
11128
11129 name = xmlXPathParseNCName(ctxt);
11130 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011131 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011132 }
11133 }
11134 return(name);
11135}
11136
11137/**
11138 * xmlXPathIsAxisName:
11139 * @name: a preparsed name token
11140 *
11141 * [6] AxisName ::= 'ancestor'
11142 * | 'ancestor-or-self'
11143 * | 'attribute'
11144 * | 'child'
11145 * | 'descendant'
11146 * | 'descendant-or-self'
11147 * | 'following'
11148 * | 'following-sibling'
11149 * | 'namespace'
11150 * | 'parent'
11151 * | 'preceding'
11152 * | 'preceding-sibling'
11153 * | 'self'
11154 *
11155 * Returns the axis or 0
11156 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011157static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +000011158xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +000011159 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011160 switch (name[0]) {
11161 case 'a':
11162 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11163 ret = AXIS_ANCESTOR;
11164 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11165 ret = AXIS_ANCESTOR_OR_SELF;
11166 if (xmlStrEqual(name, BAD_CAST "attribute"))
11167 ret = AXIS_ATTRIBUTE;
11168 break;
11169 case 'c':
11170 if (xmlStrEqual(name, BAD_CAST "child"))
11171 ret = AXIS_CHILD;
11172 break;
11173 case 'd':
11174 if (xmlStrEqual(name, BAD_CAST "descendant"))
11175 ret = AXIS_DESCENDANT;
11176 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11177 ret = AXIS_DESCENDANT_OR_SELF;
11178 break;
11179 case 'f':
11180 if (xmlStrEqual(name, BAD_CAST "following"))
11181 ret = AXIS_FOLLOWING;
11182 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11183 ret = AXIS_FOLLOWING_SIBLING;
11184 break;
11185 case 'n':
11186 if (xmlStrEqual(name, BAD_CAST "namespace"))
11187 ret = AXIS_NAMESPACE;
11188 break;
11189 case 'p':
11190 if (xmlStrEqual(name, BAD_CAST "parent"))
11191 ret = AXIS_PARENT;
11192 if (xmlStrEqual(name, BAD_CAST "preceding"))
11193 ret = AXIS_PRECEDING;
11194 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11195 ret = AXIS_PRECEDING_SIBLING;
11196 break;
11197 case 's':
11198 if (xmlStrEqual(name, BAD_CAST "self"))
11199 ret = AXIS_SELF;
11200 break;
11201 }
11202 return(ret);
11203}
11204
11205/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011206 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +000011207 * @ctxt: the XPath Parser context
11208 *
11209 * [4] Step ::= AxisSpecifier NodeTest Predicate*
Daniel Veillard45490ae2008-07-29 09:13:19 +000011210 * | AbbreviatedStep
Owen Taylor3473f882001-02-23 17:55:21 +000011211 *
11212 * [12] AbbreviatedStep ::= '.' | '..'
11213 *
11214 * [5] AxisSpecifier ::= AxisName '::'
11215 * | AbbreviatedAxisSpecifier
11216 *
11217 * [13] AbbreviatedAxisSpecifier ::= '@'?
11218 *
11219 * Modified for XPtr range support as:
11220 *
11221 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11222 * | AbbreviatedStep
11223 * | 'range-to' '(' Expr ')' Predicate*
11224 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011225 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +000011226 * A location step of . is short for self::node(). This is
11227 * particularly useful in conjunction with //. For example, the
11228 * location path .//para is short for
11229 * self::node()/descendant-or-self::node()/child::para
11230 * and so will select all para descendant elements of the context
11231 * node.
11232 * Similarly, a location step of .. is short for parent::node().
11233 * For example, ../title is short for parent::node()/child::title
11234 * and so will select the title children of the parent of the context
11235 * node.
11236 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011237static void
11238xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011239#ifdef LIBXML_XPTR_ENABLED
11240 int rangeto = 0;
11241 int op2 = -1;
11242#endif
11243
Owen Taylor3473f882001-02-23 17:55:21 +000011244 SKIP_BLANKS;
11245 if ((CUR == '.') && (NXT(1) == '.')) {
11246 SKIP(2);
11247 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011248 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11249 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011250 } else if (CUR == '.') {
11251 NEXT;
11252 SKIP_BLANKS;
11253 } else {
11254 xmlChar *name = NULL;
11255 const xmlChar *prefix = NULL;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011256 xmlXPathTestVal test = (xmlXPathTestVal) 0;
William M. Brack78637da2003-07-31 14:47:38 +000011257 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011258 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011259 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +000011260
11261 /*
11262 * The modification needed for XPointer change to the production
11263 */
11264#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011265 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +000011266 name = xmlXPathParseNCName(ctxt);
11267 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011268 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011269 xmlFree(name);
11270 SKIP_BLANKS;
11271 if (CUR != '(') {
11272 XP_ERROR(XPATH_EXPR_ERROR);
11273 }
11274 NEXT;
11275 SKIP_BLANKS;
11276
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011277 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011278 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +000011279 CHECK_ERROR;
11280
11281 SKIP_BLANKS;
11282 if (CUR != ')') {
11283 XP_ERROR(XPATH_EXPR_ERROR);
11284 }
11285 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011286 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000011287 goto eval_predicates;
11288 }
11289 }
11290#endif
Daniel Veillard2156a562001-04-28 12:24:34 +000011291 if (CUR == '*') {
11292 axis = AXIS_CHILD;
11293 } else {
11294 if (name == NULL)
11295 name = xmlXPathParseNCName(ctxt);
11296 if (name != NULL) {
11297 axis = xmlXPathIsAxisName(name);
11298 if (axis != 0) {
11299 SKIP_BLANKS;
11300 if ((CUR == ':') && (NXT(1) == ':')) {
11301 SKIP(2);
11302 xmlFree(name);
11303 name = NULL;
11304 } else {
11305 /* an element name can conflict with an axis one :-\ */
11306 axis = AXIS_CHILD;
11307 }
Owen Taylor3473f882001-02-23 17:55:21 +000011308 } else {
Owen Taylor3473f882001-02-23 17:55:21 +000011309 axis = AXIS_CHILD;
11310 }
Daniel Veillard2156a562001-04-28 12:24:34 +000011311 } else if (CUR == '@') {
11312 NEXT;
11313 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +000011314 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +000011315 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +000011316 }
Owen Taylor3473f882001-02-23 17:55:21 +000011317 }
11318
Daniel Veillard2f3523f2010-10-15 18:30:29 +020011319 if (ctxt->error != XPATH_EXPRESSION_OK) {
11320 xmlFree(name);
11321 return;
11322 }
Owen Taylor3473f882001-02-23 17:55:21 +000011323
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011324 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +000011325 if (test == 0)
11326 return;
11327
Daniel Veillarded6c5492005-07-23 15:00:22 +000011328 if ((prefix != NULL) && (ctxt->context != NULL) &&
11329 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11330 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11331 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11332 }
11333 }
Owen Taylor3473f882001-02-23 17:55:21 +000011334#ifdef DEBUG_STEP
11335 xmlGenericError(xmlGenericErrorContext,
11336 "Basis : computing new set\n");
11337#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011338
Owen Taylor3473f882001-02-23 17:55:21 +000011339#ifdef DEBUG_STEP
11340 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011341 if (ctxt->value == NULL)
11342 xmlGenericError(xmlGenericErrorContext, "no value\n");
11343 else if (ctxt->value->nodesetval == NULL)
11344 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11345 else
11346 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011347#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011348
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011349#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +000011350eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011351#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011352 op1 = ctxt->comp->last;
11353 ctxt->comp->last = -1;
11354
Owen Taylor3473f882001-02-23 17:55:21 +000011355 SKIP_BLANKS;
11356 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011357 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011358 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011359
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011360#ifdef LIBXML_XPTR_ENABLED
11361 if (rangeto) {
11362 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11363 } else
11364#endif
11365 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11366 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011367
Owen Taylor3473f882001-02-23 17:55:21 +000011368 }
11369#ifdef DEBUG_STEP
11370 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011371 if (ctxt->value == NULL)
11372 xmlGenericError(xmlGenericErrorContext, "no value\n");
11373 else if (ctxt->value->nodesetval == NULL)
11374 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11375 else
11376 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11377 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011378#endif
11379}
11380
11381/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011382 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011383 * @ctxt: the XPath Parser context
11384 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011385 * [3] RelativeLocationPath ::= Step
11386 * | RelativeLocationPath '/' Step
11387 * | AbbreviatedRelativeLocationPath
11388 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
Owen Taylor3473f882001-02-23 17:55:21 +000011389 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011390 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +000011391 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011392static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011393xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011394(xmlXPathParserContextPtr ctxt) {
11395 SKIP_BLANKS;
11396 if ((CUR == '/') && (NXT(1) == '/')) {
11397 SKIP(2);
11398 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011399 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11400 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011401 } else if (CUR == '/') {
11402 NEXT;
11403 SKIP_BLANKS;
11404 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011405 xmlXPathCompStep(ctxt);
Martin729601f2009-10-12 22:42:26 +020011406 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000011407 SKIP_BLANKS;
11408 while (CUR == '/') {
11409 if ((CUR == '/') && (NXT(1) == '/')) {
11410 SKIP(2);
11411 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011412 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +000011413 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011414 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011415 } else if (CUR == '/') {
11416 NEXT;
11417 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011418 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011419 }
11420 SKIP_BLANKS;
11421 }
11422}
11423
11424/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011425 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011426 * @ctxt: the XPath Parser context
11427 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011428 * [1] LocationPath ::= RelativeLocationPath
11429 * | AbsoluteLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011430 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
Daniel Veillard45490ae2008-07-29 09:13:19 +000011431 * | AbbreviatedAbsoluteLocationPath
11432 * [10] AbbreviatedAbsoluteLocationPath ::=
11433 * '//' RelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011434 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011435 * Compile a location path
11436 *
Owen Taylor3473f882001-02-23 17:55:21 +000011437 * // is short for /descendant-or-self::node()/. For example,
11438 * //para is short for /descendant-or-self::node()/child::para and
11439 * so will select any para element in the document (even a para element
11440 * that is a document element will be selected by //para since the
11441 * document element node is a child of the root node); div//para is
11442 * short for div/descendant-or-self::node()/child::para and so will
11443 * select all para descendants of div children.
11444 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011445static void
11446xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000011447 SKIP_BLANKS;
11448 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011449 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011450 } else {
11451 while (CUR == '/') {
11452 if ((CUR == '/') && (NXT(1) == '/')) {
11453 SKIP(2);
11454 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011455 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11456 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011457 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011458 } else if (CUR == '/') {
11459 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +000011460 SKIP_BLANKS;
11461 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +000011462 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +000011463 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011464 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011465 }
Martin729601f2009-10-12 22:42:26 +020011466 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000011467 }
11468 }
11469}
11470
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011471/************************************************************************
11472 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011473 * XPath precompiled expression evaluation *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011474 * *
11475 ************************************************************************/
11476
Daniel Veillardf06307e2001-07-03 10:35:50 +000011477static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011478xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11479
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011480#ifdef DEBUG_STEP
11481static void
Daniel Veillard074f37e2008-09-01 13:38:22 +000011482xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011483 int nbNodes)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011484{
Daniel Veillardf06307e2001-07-03 10:35:50 +000011485 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillard074f37e2008-09-01 13:38:22 +000011486 switch (op->value) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011487 case AXIS_ANCESTOR:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011488 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011489 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011490 case AXIS_ANCESTOR_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011491 xmlGenericError(xmlGenericErrorContext,
11492 "axis 'ancestors-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011493 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011494 case AXIS_ATTRIBUTE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011495 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011496 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011497 case AXIS_CHILD:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011498 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011499 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011500 case AXIS_DESCENDANT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011501 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011502 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011503 case AXIS_DESCENDANT_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011504 xmlGenericError(xmlGenericErrorContext,
11505 "axis 'descendant-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011506 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011507 case AXIS_FOLLOWING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011508 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011509 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011510 case AXIS_FOLLOWING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011511 xmlGenericError(xmlGenericErrorContext,
11512 "axis 'following-siblings' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011513 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011514 case AXIS_NAMESPACE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011515 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011516 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011517 case AXIS_PARENT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011518 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011519 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011520 case AXIS_PRECEDING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011521 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011522 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011523 case AXIS_PRECEDING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011524 xmlGenericError(xmlGenericErrorContext,
11525 "axis 'preceding-sibling' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011526 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011527 case AXIS_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011528 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011529 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011530 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011531 xmlGenericError(xmlGenericErrorContext,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011532 " context contains %d nodes\n", nbNodes);
Daniel Veillard074f37e2008-09-01 13:38:22 +000011533 switch (op->value2) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011534 case NODE_TEST_NONE:
11535 xmlGenericError(xmlGenericErrorContext,
11536 " searching for none !!!\n");
11537 break;
11538 case NODE_TEST_TYPE:
11539 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011540 " searching for type %d\n", op->value3);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011541 break;
11542 case NODE_TEST_PI:
11543 xmlGenericError(xmlGenericErrorContext,
11544 " searching for PI !!!\n");
11545 break;
11546 case NODE_TEST_ALL:
11547 xmlGenericError(xmlGenericErrorContext,
11548 " searching for *\n");
11549 break;
11550 case NODE_TEST_NS:
11551 xmlGenericError(xmlGenericErrorContext,
11552 " searching for namespace %s\n",
Daniel Veillard074f37e2008-09-01 13:38:22 +000011553 op->value5);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011554 break;
11555 case NODE_TEST_NAME:
11556 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011557 " searching for name %s\n", op->value5);
11558 if (op->value4)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011559 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011560 " with namespace %s\n", op->value4);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011561 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011562 }
11563 xmlGenericError(xmlGenericErrorContext, "Testing : ");
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011564}
11565#endif /* DEBUG_STEP */
11566
11567static int
11568xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11569 xmlXPathStepOpPtr op,
11570 xmlNodeSetPtr set,
11571 int contextSize,
11572 int hasNsNodes)
11573{
11574 if (op->ch1 != -1) {
11575 xmlXPathCompExprPtr comp = ctxt->comp;
11576 /*
11577 * Process inner predicates first.
11578 */
11579 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11580 /*
11581 * TODO: raise an internal error.
11582 */
11583 }
11584 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11585 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11586 CHECK_ERROR0;
11587 if (contextSize <= 0)
11588 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011589 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011590 if (op->ch2 != -1) {
11591 xmlXPathContextPtr xpctxt = ctxt->context;
11592 xmlNodePtr contextNode, oldContextNode;
11593 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011594 int i, res, contextPos = 0, newContextSize;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011595 xmlXPathStepOpPtr exprOp;
11596 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11597
11598#ifdef LIBXML_XPTR_ENABLED
11599 /*
11600 * URGENT TODO: Check the following:
11601 * We don't expect location sets if evaluating prediates, right?
11602 * Only filters should expect location sets, right?
11603 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011604#endif
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011605 /*
11606 * SPEC XPath 1.0:
11607 * "For each node in the node-set to be filtered, the
11608 * PredicateExpr is evaluated with that node as the
11609 * context node, with the number of nodes in the
11610 * node-set as the context size, and with the proximity
11611 * position of the node in the node-set with respect to
11612 * the axis as the context position;"
11613 * @oldset is the node-set" to be filtered.
11614 *
11615 * SPEC XPath 1.0:
11616 * "only predicates change the context position and
11617 * context size (see [2.4 Predicates])."
11618 * Example:
11619 * node-set context pos
11620 * nA 1
11621 * nB 2
11622 * nC 3
11623 * After applying predicate [position() > 1] :
11624 * node-set context pos
11625 * nB 1
11626 * nC 2
11627 */
11628 oldContextNode = xpctxt->node;
11629 oldContextDoc = xpctxt->doc;
11630 /*
11631 * Get the expression of this predicate.
11632 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000011633 exprOp = &ctxt->comp->steps[op->ch2];
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011634 newContextSize = 0;
11635 for (i = 0; i < set->nodeNr; i++) {
11636 if (set->nodeTab[i] == NULL)
11637 continue;
11638
11639 contextNode = set->nodeTab[i];
11640 xpctxt->node = contextNode;
11641 xpctxt->contextSize = contextSize;
11642 xpctxt->proximityPosition = ++contextPos;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011643
11644 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011645 * Also set the xpath document in case things like
11646 * key() are evaluated in the predicate.
11647 */
11648 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11649 (contextNode->doc != NULL))
11650 xpctxt->doc = contextNode->doc;
11651 /*
11652 * Evaluate the predicate expression with 1 context node
11653 * at a time; this node is packaged into a node set; this
11654 * node set is handed over to the evaluation mechanism.
11655 */
11656 if (contextObj == NULL)
11657 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11658 else
11659 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11660 contextNode);
11661
11662 valuePush(ctxt, contextObj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011663
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011664 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011665
William M. Brack0bcec062007-02-14 02:15:19 +000011666 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11667 xmlXPathNodeSetClear(set, hasNsNodes);
11668 newContextSize = 0;
11669 goto evaluation_exit;
11670 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011671
11672 if (res != 0) {
11673 newContextSize++;
11674 } else {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011675 /*
11676 * Remove the entry from the initial node set.
11677 */
11678 set->nodeTab[i] = NULL;
11679 if (contextNode->type == XML_NAMESPACE_DECL)
11680 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011681 }
11682 if (ctxt->value == contextObj) {
11683 /*
11684 * Don't free the temporary XPath object holding the
11685 * context node, in order to avoid massive recreation
11686 * inside this loop.
11687 */
11688 valuePop(ctxt);
11689 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11690 } else {
11691 /*
11692 * TODO: The object was lost in the evaluation machinery.
11693 * Can this happen? Maybe in internal-error cases.
11694 */
11695 contextObj = NULL;
11696 }
11697 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011698
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011699 if (contextObj != NULL) {
11700 if (ctxt->value == contextObj)
11701 valuePop(ctxt);
11702 xmlXPathReleaseObject(xpctxt, contextObj);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011703 }
William M. Brack0bcec062007-02-14 02:15:19 +000011704evaluation_exit:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011705 if (exprRes != NULL)
11706 xmlXPathReleaseObject(ctxt->context, exprRes);
11707 /*
11708 * Reset/invalidate the context.
11709 */
11710 xpctxt->node = oldContextNode;
11711 xpctxt->doc = oldContextDoc;
11712 xpctxt->contextSize = -1;
11713 xpctxt->proximityPosition = -1;
11714 return(newContextSize);
11715 }
11716 return(contextSize);
11717}
11718
11719static int
11720xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11721 xmlXPathStepOpPtr op,
11722 xmlNodeSetPtr set,
11723 int contextSize,
11724 int minPos,
11725 int maxPos,
11726 int hasNsNodes)
11727{
11728 if (op->ch1 != -1) {
11729 xmlXPathCompExprPtr comp = ctxt->comp;
11730 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11731 /*
11732 * TODO: raise an internal error.
11733 */
11734 }
11735 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11736 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11737 CHECK_ERROR0;
11738 if (contextSize <= 0)
11739 return(0);
11740 }
11741 /*
11742 * Check if the node set contains a sufficient number of nodes for
11743 * the requested range.
11744 */
11745 if (contextSize < minPos) {
11746 xmlXPathNodeSetClear(set, hasNsNodes);
11747 return(0);
11748 }
11749 if (op->ch2 == -1) {
11750 /*
11751 * TODO: Can this ever happen?
11752 */
11753 return (contextSize);
11754 } else {
11755 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011756 int i, pos = 0, newContextSize = 0, contextPos = 0, res;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011757 xmlXPathStepOpPtr exprOp;
11758 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11759 xmlNodePtr oldContextNode, contextNode = NULL;
11760 xmlXPathContextPtr xpctxt = ctxt->context;
Daniel Veillardf5048b32011-08-18 17:10:13 +080011761 int frame;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011762
11763#ifdef LIBXML_XPTR_ENABLED
11764 /*
11765 * URGENT TODO: Check the following:
11766 * We don't expect location sets if evaluating prediates, right?
11767 * Only filters should expect location sets, right?
11768 */
11769#endif /* LIBXML_XPTR_ENABLED */
11770
11771 /*
11772 * Save old context.
11773 */
11774 oldContextNode = xpctxt->node;
11775 oldContextDoc = xpctxt->doc;
11776 /*
11777 * Get the expression of this predicate.
11778 */
11779 exprOp = &ctxt->comp->steps[op->ch2];
11780 for (i = 0; i < set->nodeNr; i++) {
Daniel Veillardf5048b32011-08-18 17:10:13 +080011781 xmlXPathObjectPtr tmp;
11782
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011783 if (set->nodeTab[i] == NULL)
11784 continue;
11785
11786 contextNode = set->nodeTab[i];
11787 xpctxt->node = contextNode;
11788 xpctxt->contextSize = contextSize;
11789 xpctxt->proximityPosition = ++contextPos;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011790
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011791 /*
11792 * Initialize the new set.
11793 * Also set the xpath document in case things like
11794 * key() evaluation are attempted on the predicate
11795 */
11796 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11797 (contextNode->doc != NULL))
11798 xpctxt->doc = contextNode->doc;
11799 /*
11800 * Evaluate the predicate expression with 1 context node
11801 * at a time; this node is packaged into a node set; this
11802 * node set is handed over to the evaluation mechanism.
11803 */
11804 if (contextObj == NULL)
11805 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11806 else
11807 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11808 contextNode);
11809
Daniel Veillardf5048b32011-08-18 17:10:13 +080011810 frame = xmlXPathSetFrame(ctxt);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011811 valuePush(ctxt, contextObj);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011812 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Daniel Veillardf5048b32011-08-18 17:10:13 +080011813 tmp = valuePop(ctxt);
11814 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011815
William M. Brackf1794562007-08-23 12:58:13 +000011816 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
Daniel Veillardf5048b32011-08-18 17:10:13 +080011817 while (tmp != contextObj) {
Daniel Veillarddf83c172010-11-17 14:12:14 +010011818 /*
11819 * Free up the result
11820 * then pop off contextObj, which will be freed later
11821 */
11822 xmlXPathReleaseObject(xpctxt, tmp);
Daniel Veillardf5048b32011-08-18 17:10:13 +080011823 tmp = valuePop(ctxt);
Daniel Veillardfec31bc2010-11-18 11:07:24 +010011824 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011825 goto evaluation_error;
William M. Brackf1794562007-08-23 12:58:13 +000011826 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080011827 /* push the result back onto the stack */
11828 valuePush(ctxt, tmp);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011829
11830 if (res)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011831 pos++;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011832
11833 if (res && (pos >= minPos) && (pos <= maxPos)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011834 /*
11835 * Fits in the requested range.
11836 */
11837 newContextSize++;
11838 if (minPos == maxPos) {
11839 /*
11840 * Only 1 node was requested.
11841 */
11842 if (contextNode->type == XML_NAMESPACE_DECL) {
11843 /*
11844 * As always: take care of those nasty
11845 * namespace nodes.
11846 */
11847 set->nodeTab[i] = NULL;
11848 }
11849 xmlXPathNodeSetClear(set, hasNsNodes);
11850 set->nodeNr = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011851 set->nodeTab[0] = contextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011852 goto evaluation_exit;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011853 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011854 if (pos == maxPos) {
11855 /*
11856 * We are done.
11857 */
11858 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11859 goto evaluation_exit;
11860 }
11861 } else {
11862 /*
11863 * Remove the entry from the initial node set.
11864 */
11865 set->nodeTab[i] = NULL;
11866 if (contextNode->type == XML_NAMESPACE_DECL)
11867 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11868 }
11869 if (exprRes != NULL) {
11870 xmlXPathReleaseObject(ctxt->context, exprRes);
11871 exprRes = NULL;
11872 }
11873 if (ctxt->value == contextObj) {
11874 /*
11875 * Don't free the temporary XPath object holding the
11876 * context node, in order to avoid massive recreation
11877 * inside this loop.
11878 */
11879 valuePop(ctxt);
11880 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11881 } else {
11882 /*
11883 * The object was lost in the evaluation machinery.
11884 * Can this happen? Maybe in case of internal-errors.
11885 */
11886 contextObj = NULL;
11887 }
11888 }
11889 goto evaluation_exit;
11890
11891evaluation_error:
11892 xmlXPathNodeSetClear(set, hasNsNodes);
11893 newContextSize = 0;
11894
11895evaluation_exit:
11896 if (contextObj != NULL) {
11897 if (ctxt->value == contextObj)
11898 valuePop(ctxt);
11899 xmlXPathReleaseObject(xpctxt, contextObj);
11900 }
11901 if (exprRes != NULL)
11902 xmlXPathReleaseObject(ctxt->context, exprRes);
11903 /*
11904 * Reset/invalidate the context.
11905 */
11906 xpctxt->node = oldContextNode;
11907 xpctxt->doc = oldContextDoc;
11908 xpctxt->contextSize = -1;
11909 xpctxt->proximityPosition = -1;
11910 return(newContextSize);
11911 }
11912 return(contextSize);
11913}
11914
11915static int
11916xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
Daniel Veillard45490ae2008-07-29 09:13:19 +000011917 xmlXPathStepOpPtr op,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011918 int *maxPos)
11919{
11920
11921 xmlXPathStepOpPtr exprOp;
11922
11923 /*
11924 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11925 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000011926
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011927 /*
11928 * If not -1, then ch1 will point to:
11929 * 1) For predicates (XPATH_OP_PREDICATE):
11930 * - an inner predicate operator
11931 * 2) For filters (XPATH_OP_FILTER):
11932 * - an inner filter operater OR
11933 * - an expression selecting the node set.
11934 * E.g. "key('a', 'b')" or "(//foo | //bar)".
Daniel Veillard45490ae2008-07-29 09:13:19 +000011935 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011936 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11937 return(0);
11938
11939 if (op->ch2 != -1) {
11940 exprOp = &ctxt->comp->steps[op->ch2];
Daniel Veillard45490ae2008-07-29 09:13:19 +000011941 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011942 return(0);
11943
11944 if ((exprOp != NULL) &&
11945 (exprOp->op == XPATH_OP_VALUE) &&
11946 (exprOp->value4 != NULL) &&
11947 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11948 {
11949 /*
11950 * We have a "[n]" predicate here.
11951 * TODO: Unfortunately this simplistic test here is not
11952 * able to detect a position() predicate in compound
11953 * expressions like "[@attr = 'a" and position() = 1],
11954 * and even not the usage of position() in
11955 * "[position() = 1]"; thus - obviously - a position-range,
11956 * like it "[position() < 5]", is also not detected.
11957 * Maybe we could rewrite the AST to ease the optimization.
11958 */
11959 *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011960
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011961 if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
11962 (float) *maxPos)
Daniel Veillard45490ae2008-07-29 09:13:19 +000011963 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011964 return(1);
11965 }
11966 }
11967 return(0);
11968}
11969
11970static int
11971xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11972 xmlXPathStepOpPtr op,
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011973 xmlNodePtr * first, xmlNodePtr * last,
11974 int toBool)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011975{
11976
11977#define XP_TEST_HIT \
11978 if (hasAxisRange != 0) { \
11979 if (++pos == maxPos) { \
11980 addNode(seq, cur); \
11981 goto axis_range_end; } \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011982 } else { \
11983 addNode(seq, cur); \
11984 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011985
11986#define XP_TEST_HIT_NS \
11987 if (hasAxisRange != 0) { \
11988 if (++pos == maxPos) { \
11989 hasNsNodes = 1; \
11990 xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
11991 goto axis_range_end; } \
11992 } else { \
11993 hasNsNodes = 1; \
11994 xmlXPathNodeSetAddNs(seq, \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011995 xpctxt->node, (xmlNsPtr) cur); \
11996 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011997
11998 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11999 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12000 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12001 const xmlChar *prefix = op->value4;
12002 const xmlChar *name = op->value5;
12003 const xmlChar *URI = NULL;
12004
12005#ifdef DEBUG_STEP
12006 int nbMatches = 0, prevMatches = 0;
12007#endif
12008 int total = 0, hasNsNodes = 0;
12009 /* The popped object holding the context nodes */
12010 xmlXPathObjectPtr obj;
12011 /* The set of context nodes for the node tests */
12012 xmlNodeSetPtr contextSeq;
12013 int contextIdx;
12014 xmlNodePtr contextNode;
12015 /* The context node for a compound traversal */
12016 xmlNodePtr outerContextNode;
12017 /* The final resulting node set wrt to all context nodes */
12018 xmlNodeSetPtr outSeq;
12019 /*
12020 * The temporary resulting node set wrt 1 context node.
12021 * Used to feed predicate evaluation.
12022 */
12023 xmlNodeSetPtr seq;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012024 xmlNodePtr cur;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012025 /* First predicate operator */
12026 xmlXPathStepOpPtr predOp;
12027 int maxPos; /* The requested position() (when a "[n]" predicate) */
12028 int hasPredicateRange, hasAxisRange, pos, size, newSize;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012029 int breakOnFirstHit;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012030
12031 xmlXPathTraversalFunction next = NULL;
12032 /* compound axis traversal */
12033 xmlXPathTraversalFunctionExt outerNext = NULL;
12034 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12035 xmlXPathNodeSetMergeFunction mergeAndClear;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012036 xmlNodePtr oldContextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012037 xmlXPathContextPtr xpctxt = ctxt->context;
12038
12039
12040 CHECK_TYPE0(XPATH_NODESET);
12041 obj = valuePop(ctxt);
12042 /*
12043 * Setup namespaces.
12044 */
12045 if (prefix != NULL) {
12046 URI = xmlXPathNsLookup(xpctxt, prefix);
12047 if (URI == NULL) {
12048 xmlXPathReleaseObject(xpctxt, obj);
12049 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12050 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012051 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012052 /*
12053 * Setup axis.
12054 *
12055 * MAYBE FUTURE TODO: merging optimizations:
12056 * - If the nodes to be traversed wrt to the initial nodes and
12057 * the current axis cannot overlap, then we could avoid searching
12058 * for duplicates during the merge.
12059 * But the question is how/when to evaluate if they cannot overlap.
12060 * Example: if we know that for two initial nodes, the one is
12061 * not in the ancestor-or-self axis of the other, then we could safely
12062 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12063 * the descendant-or-self axis.
12064 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012065 mergeAndClear = xmlXPathNodeSetMergeAndClear;
12066 switch (axis) {
12067 case AXIS_ANCESTOR:
12068 first = NULL;
12069 next = xmlXPathNextAncestor;
12070 break;
12071 case AXIS_ANCESTOR_OR_SELF:
12072 first = NULL;
12073 next = xmlXPathNextAncestorOrSelf;
12074 break;
12075 case AXIS_ATTRIBUTE:
12076 first = NULL;
12077 last = NULL;
12078 next = xmlXPathNextAttribute;
12079 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12080 break;
12081 case AXIS_CHILD:
12082 last = NULL;
12083 if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
12084 /*
12085 * This iterator will give us only nodes which can
12086 * hold element nodes.
12087 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000012088 outerNext = xmlXPathNextDescendantOrSelfElemParent;
12089 }
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)) {
12225 if (outerNext != NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012226 /*
12227 * This is a compound traversal.
12228 */
12229 if (contextNode == NULL) {
12230 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012231 * Set the context for the outer traversal.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012232 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012233 outerContextNode = contextSeq->nodeTab[contextIdx++];
12234 contextNode = outerNext(NULL, outerContextNode);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012235 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012236 contextNode = outerNext(contextNode, outerContextNode);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012237 if (contextNode == NULL)
12238 continue;
12239 /*
12240 * Set the context for the main traversal.
12241 */
12242 xpctxt->node = contextNode;
12243 } else
Daniel Veillard45490ae2008-07-29 09:13:19 +000012244 xpctxt->node = contextSeq->nodeTab[contextIdx++];
12245
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012246 if (seq == NULL) {
12247 seq = xmlXPathNodeSetCreate(NULL);
12248 if (seq == NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012249 total = 0;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012250 goto error;
12251 }
12252 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012253 /*
12254 * Traverse the axis and test the nodes.
12255 */
12256 pos = 0;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012257 cur = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012258 hasNsNodes = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012259 do {
12260 cur = next(ctxt, cur);
12261 if (cur == NULL)
12262 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012263
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012264 /*
12265 * QUESTION TODO: What does the "first" and "last" stuff do?
12266 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012267 if ((first != NULL) && (*first != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012268 if (*first == cur)
12269 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012270 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012271#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012272 (xmlXPathCmpNodesExt(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012273#else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012274 (xmlXPathCmpNodes(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012275#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012276 {
12277 break;
12278 }
12279 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012280 if ((last != NULL) && (*last != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012281 if (*last == cur)
12282 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012283 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012284#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012285 (xmlXPathCmpNodesExt(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012286#else
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012287 (xmlXPathCmpNodes(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012288#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012289 {
12290 break;
12291 }
12292 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012293
12294 total++;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012295
Daniel Veillardf06307e2001-07-03 10:35:50 +000012296#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012297 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12298#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +000012299
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012300 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012301 case NODE_TEST_NONE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012302 total = 0;
12303 STRANGE
12304 goto error;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012305 case NODE_TEST_TYPE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012306 /*
12307 * TODO: Don't we need to use
12308 * xmlXPathNodeSetAddNs() for namespace nodes here?
12309 * Surprisingly, some c14n tests fail, if we do this.
12310 */
12311 if (type == NODE_TYPE_NODE) {
12312 switch (cur->type) {
12313 case XML_DOCUMENT_NODE:
12314 case XML_HTML_DOCUMENT_NODE:
12315#ifdef LIBXML_DOCB_ENABLED
12316 case XML_DOCB_DOCUMENT_NODE:
12317#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +000012318 case XML_ELEMENT_NODE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012319 case XML_ATTRIBUTE_NODE:
12320 case XML_PI_NODE:
12321 case XML_COMMENT_NODE:
12322 case XML_CDATA_SECTION_NODE:
12323 case XML_TEXT_NODE:
12324 case XML_NAMESPACE_DECL:
12325 XP_TEST_HIT
12326 break;
12327 default:
12328 break;
12329 }
12330 } else if (cur->type == type) {
Kasimier T. Buchcik889b7622006-07-03 11:44:13 +000012331 if (type == XML_NAMESPACE_DECL)
12332 XP_TEST_HIT_NS
12333 else
12334 XP_TEST_HIT
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012335 } else if ((type == NODE_TYPE_TEXT) &&
12336 (cur->type == XML_CDATA_SECTION_NODE))
12337 {
12338 XP_TEST_HIT
12339 }
12340 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012341 case NODE_TEST_PI:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012342 if ((cur->type == XML_PI_NODE) &&
12343 ((name == NULL) || xmlStrEqual(name, cur->name)))
12344 {
12345 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012346 }
12347 break;
12348 case NODE_TEST_ALL:
12349 if (axis == AXIS_ATTRIBUTE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012350 if (cur->type == XML_ATTRIBUTE_NODE)
12351 {
12352 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012353 }
12354 } else if (axis == AXIS_NAMESPACE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012355 if (cur->type == XML_NAMESPACE_DECL)
12356 {
12357 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012358 }
12359 } else {
12360 if (cur->type == XML_ELEMENT_NODE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012361 if (prefix == NULL)
12362 {
12363 XP_TEST_HIT
12364
Daniel Veillardf06307e2001-07-03 10:35:50 +000012365 } else if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012366 (xmlStrEqual(URI, cur->ns->href)))
12367 {
12368 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012369 }
12370 }
12371 }
12372 break;
12373 case NODE_TEST_NS:{
12374 TODO;
12375 break;
12376 }
12377 case NODE_TEST_NAME:
Daniel Veillardfe3970e2006-11-23 16:08:30 +000012378 if (axis == AXIS_ATTRIBUTE) {
12379 if (cur->type != XML_ATTRIBUTE_NODE)
12380 break;
12381 } else if (axis == AXIS_NAMESPACE) {
12382 if (cur->type != XML_NAMESPACE_DECL)
12383 break;
12384 } else {
12385 if (cur->type != XML_ELEMENT_NODE)
12386 break;
12387 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012388 switch (cur->type) {
12389 case XML_ELEMENT_NODE:
12390 if (xmlStrEqual(name, cur->name)) {
12391 if (prefix == NULL) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012392 if (cur->ns == NULL)
12393 {
12394 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012395 }
12396 } else {
12397 if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012398 (xmlStrEqual(URI, cur->ns->href)))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012399 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012400 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012401 }
12402 }
12403 }
12404 break;
12405 case XML_ATTRIBUTE_NODE:{
12406 xmlAttrPtr attr = (xmlAttrPtr) cur;
12407
12408 if (xmlStrEqual(name, attr->name)) {
12409 if (prefix == NULL) {
12410 if ((attr->ns == NULL) ||
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012411 (attr->ns->prefix == NULL))
12412 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012413 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012414 }
12415 } else {
12416 if ((attr->ns != NULL) &&
12417 (xmlStrEqual(URI,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012418 attr->ns->href)))
12419 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012420 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012421 }
12422 }
12423 }
12424 break;
12425 }
12426 case XML_NAMESPACE_DECL:
12427 if (cur->type == XML_NAMESPACE_DECL) {
12428 xmlNsPtr ns = (xmlNsPtr) cur;
12429
12430 if ((ns->prefix != NULL) && (name != NULL)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012431 && (xmlStrEqual(ns->prefix, name)))
12432 {
12433 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012434 }
12435 }
12436 break;
12437 default:
12438 break;
12439 }
12440 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012441 } /* switch(test) */
12442 } while (cur != NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012443
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012444 goto apply_predicates;
12445
Daniel Veillard45490ae2008-07-29 09:13:19 +000012446axis_range_end: /* ----------------------------------------------------- */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012447 /*
12448 * We have a "/foo[n]", and position() = n was reached.
12449 * Note that we can have as well "/foo/::parent::foo[1]", so
12450 * a duplicate-aware merge is still needed.
12451 * Merge with the result.
12452 */
12453 if (outSeq == NULL) {
12454 outSeq = seq;
12455 seq = NULL;
12456 } else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012457 outSeq = mergeAndClear(outSeq, seq, 0);
12458 /*
12459 * Break if only a true/false result was requested.
12460 */
12461 if (toBool)
12462 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012463 continue;
12464
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012465first_hit: /* ---------------------------------------------------------- */
12466 /*
12467 * Break if only a true/false result was requested and
12468 * no predicates existed and a node test succeeded.
12469 */
12470 if (outSeq == NULL) {
12471 outSeq = seq;
12472 seq = NULL;
12473 } else
12474 outSeq = mergeAndClear(outSeq, seq, 0);
12475 break;
12476
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012477#ifdef DEBUG_STEP
12478 if (seq != NULL)
12479 nbMatches += seq->nodeNr;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012480#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012481
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012482apply_predicates: /* --------------------------------------------------- */
12483 /*
12484 * Apply predicates.
Daniel Veillard45490ae2008-07-29 09:13:19 +000012485 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012486 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12487 /*
12488 * E.g. when we have a "/foo[some expression][n]".
Daniel Veillard45490ae2008-07-29 09:13:19 +000012489 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012490 /*
12491 * QUESTION TODO: The old predicate evaluation took into
12492 * account location-sets.
12493 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12494 * Do we expect such a set here?
12495 * All what I learned now from the evaluation semantics
12496 * does not indicate that a location-set will be processed
12497 * here, so this looks OK.
Daniel Veillard45490ae2008-07-29 09:13:19 +000012498 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012499 /*
12500 * Iterate over all predicates, starting with the outermost
12501 * predicate.
12502 * TODO: Problem: we cannot execute the inner predicates first
12503 * since we cannot go back *up* the operator tree!
12504 * Options we have:
12505 * 1) Use of recursive functions (like is it currently done
12506 * via xmlXPathCompOpEval())
12507 * 2) Add a predicate evaluation information stack to the
12508 * context struct
12509 * 3) Change the way the operators are linked; we need a
12510 * "parent" field on xmlXPathStepOp
12511 *
12512 * For the moment, I'll try to solve this with a recursive
12513 * function: xmlXPathCompOpEvalPredicate().
Daniel Veillard45490ae2008-07-29 09:13:19 +000012514 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012515 size = seq->nodeNr;
12516 if (hasPredicateRange != 0)
12517 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12518 predOp, seq, size, maxPos, maxPos, hasNsNodes);
12519 else
12520 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12521 predOp, seq, size, hasNsNodes);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012522
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012523 if (ctxt->error != XPATH_EXPRESSION_OK) {
12524 total = 0;
12525 goto error;
12526 }
12527 /*
12528 * Add the filtered set of nodes to the result node set.
12529 */
12530 if (newSize == 0) {
12531 /*
12532 * The predicates filtered all nodes out.
12533 */
12534 xmlXPathNodeSetClear(seq, hasNsNodes);
12535 } else if (seq->nodeNr > 0) {
12536 /*
12537 * Add to result set.
12538 */
12539 if (outSeq == NULL) {
12540 if (size != newSize) {
12541 /*
12542 * We need to merge and clear here, since
12543 * the sequence will contained NULLed entries.
12544 */
12545 outSeq = mergeAndClear(NULL, seq, 1);
12546 } else {
12547 outSeq = seq;
12548 seq = NULL;
12549 }
12550 } else
12551 outSeq = mergeAndClear(outSeq, seq,
12552 (size != newSize) ? 1: 0);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012553 /*
12554 * Break if only a true/false result was requested.
12555 */
12556 if (toBool)
12557 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012558 }
12559 } else if (seq->nodeNr > 0) {
12560 /*
12561 * Add to result set.
12562 */
12563 if (outSeq == NULL) {
12564 outSeq = seq;
12565 seq = NULL;
12566 } else {
12567 outSeq = mergeAndClear(outSeq, seq, 0);
12568 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012569 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012570 }
12571
12572error:
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012573 if ((obj->boolval) && (obj->user != NULL)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012574 /*
12575 * QUESTION TODO: What does this do and why?
12576 * TODO: Do we have to do this also for the "error"
12577 * cleanup further down?
12578 */
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012579 ctxt->value->boolval = 1;
12580 ctxt->value->user = obj->user;
12581 obj->user = NULL;
12582 obj->boolval = 0;
12583 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012584 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012585
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012586 /*
12587 * Ensure we return at least an emtpy set.
12588 */
12589 if (outSeq == NULL) {
12590 if ((seq != NULL) && (seq->nodeNr == 0))
12591 outSeq = seq;
12592 else
12593 outSeq = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +000012594 /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012595 }
12596 if ((seq != NULL) && (seq != outSeq)) {
12597 xmlXPathFreeNodeSet(seq);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012598 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012599 /*
12600 * Hand over the result. Better to push the set also in
12601 * case of errors.
12602 */
12603 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12604 /*
12605 * Reset the context node.
12606 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012607 xpctxt->node = oldContextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012608
12609#ifdef DEBUG_STEP
12610 xmlGenericError(xmlGenericErrorContext,
12611 "\nExamined %d nodes, found %d nodes at that step\n",
12612 total, nbMatches);
12613#endif
12614
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012615 return(total);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012616}
12617
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012618static int
12619xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12620 xmlXPathStepOpPtr op, xmlNodePtr * first);
12621
Daniel Veillardf06307e2001-07-03 10:35:50 +000012622/**
12623 * xmlXPathCompOpEvalFirst:
12624 * @ctxt: the XPath parser context with the compiled expression
12625 * @op: an XPath compiled operation
12626 * @first: the first elem found so far
12627 *
12628 * Evaluate the Precompiled XPath operation searching only the first
12629 * element in document order
12630 *
12631 * Returns the number of examined objects.
12632 */
12633static int
12634xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12635 xmlXPathStepOpPtr op, xmlNodePtr * first)
12636{
12637 int total = 0, cur;
12638 xmlXPathCompExprPtr comp;
12639 xmlXPathObjectPtr arg1, arg2;
12640
Daniel Veillard556c6682001-10-06 09:59:51 +000012641 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012642 comp = ctxt->comp;
12643 switch (op->op) {
12644 case XPATH_OP_END:
12645 return (0);
12646 case XPATH_OP_UNION:
12647 total =
12648 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12649 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012650 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012651 if ((ctxt->value != NULL)
12652 && (ctxt->value->type == XPATH_NODESET)
12653 && (ctxt->value->nodesetval != NULL)
12654 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12655 /*
12656 * limit tree traversing to first node in the result
12657 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012658 /*
12659 * OPTIMIZE TODO: This implicitely sorts
12660 * the result, even if not needed. E.g. if the argument
12661 * of the count() function, no sorting is needed.
12662 * OPTIMIZE TODO: How do we know if the node-list wasn't
12663 * aready sorted?
12664 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012665 if (ctxt->value->nodesetval->nodeNr > 1)
12666 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012667 *first = ctxt->value->nodesetval->nodeTab[0];
12668 }
12669 cur =
12670 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12671 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012672 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012673 CHECK_TYPE0(XPATH_NODESET);
12674 arg2 = valuePop(ctxt);
12675
12676 CHECK_TYPE0(XPATH_NODESET);
12677 arg1 = valuePop(ctxt);
12678
12679 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12680 arg2->nodesetval);
12681 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012682 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012683 /* optimizer */
12684 if (total > cur)
12685 xmlXPathCompSwap(op);
12686 return (total + cur);
12687 case XPATH_OP_ROOT:
12688 xmlXPathRoot(ctxt);
12689 return (0);
12690 case XPATH_OP_NODE:
12691 if (op->ch1 != -1)
12692 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012693 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012694 if (op->ch2 != -1)
12695 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012696 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012697 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12698 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012699 return (total);
12700 case XPATH_OP_RESET:
12701 if (op->ch1 != -1)
12702 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012703 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012704 if (op->ch2 != -1)
12705 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012706 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012707 ctxt->context->node = NULL;
12708 return (total);
12709 case XPATH_OP_COLLECT:{
12710 if (op->ch1 == -1)
12711 return (total);
12712
12713 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012714 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012715
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012716 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012717 return (total);
12718 }
12719 case XPATH_OP_VALUE:
12720 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012721 xmlXPathCacheObjectCopy(ctxt->context,
12722 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012723 return (0);
12724 case XPATH_OP_SORT:
12725 if (op->ch1 != -1)
12726 total +=
12727 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12728 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012729 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012730 if ((ctxt->value != NULL)
12731 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012732 && (ctxt->value->nodesetval != NULL)
12733 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012734 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12735 return (total);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012736#ifdef XP_OPTIMIZED_FILTER_FIRST
12737 case XPATH_OP_FILTER:
Marius Wachtler2ddecc22010-10-12 09:09:07 +020012738 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012739 return (total);
12740#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000012741 default:
12742 return (xmlXPathCompOpEval(ctxt, op));
12743 }
12744}
12745
12746/**
12747 * xmlXPathCompOpEvalLast:
12748 * @ctxt: the XPath parser context with the compiled expression
12749 * @op: an XPath compiled operation
12750 * @last: the last elem found so far
12751 *
12752 * Evaluate the Precompiled XPath operation searching only the last
12753 * element in document order
12754 *
William M. Brack08171912003-12-29 02:52:11 +000012755 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000012756 */
12757static int
12758xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12759 xmlNodePtr * last)
12760{
12761 int total = 0, cur;
12762 xmlXPathCompExprPtr comp;
12763 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +000012764 xmlNodePtr bak;
12765 xmlDocPtr bakd;
12766 int pp;
12767 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012768
Daniel Veillard556c6682001-10-06 09:59:51 +000012769 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012770 comp = ctxt->comp;
12771 switch (op->op) {
12772 case XPATH_OP_END:
12773 return (0);
12774 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +000012775 bakd = ctxt->context->doc;
12776 bak = ctxt->context->node;
12777 pp = ctxt->context->proximityPosition;
12778 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012779 total =
12780 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012781 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012782 if ((ctxt->value != NULL)
12783 && (ctxt->value->type == XPATH_NODESET)
12784 && (ctxt->value->nodesetval != NULL)
12785 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12786 /*
12787 * limit tree traversing to first node in the result
12788 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012789 if (ctxt->value->nodesetval->nodeNr > 1)
12790 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012791 *last =
12792 ctxt->value->nodesetval->nodeTab[ctxt->value->
12793 nodesetval->nodeNr -
12794 1];
12795 }
William M. Brackce4fc562004-01-22 02:47:18 +000012796 ctxt->context->doc = bakd;
12797 ctxt->context->node = bak;
12798 ctxt->context->proximityPosition = pp;
12799 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012800 cur =
12801 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012802 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012803 if ((ctxt->value != NULL)
12804 && (ctxt->value->type == XPATH_NODESET)
12805 && (ctxt->value->nodesetval != NULL)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012806 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012807 }
12808 CHECK_TYPE0(XPATH_NODESET);
12809 arg2 = valuePop(ctxt);
12810
12811 CHECK_TYPE0(XPATH_NODESET);
12812 arg1 = valuePop(ctxt);
12813
12814 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12815 arg2->nodesetval);
12816 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012817 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012818 /* optimizer */
12819 if (total > cur)
12820 xmlXPathCompSwap(op);
12821 return (total + cur);
12822 case XPATH_OP_ROOT:
12823 xmlXPathRoot(ctxt);
12824 return (0);
12825 case XPATH_OP_NODE:
12826 if (op->ch1 != -1)
12827 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012828 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012829 if (op->ch2 != -1)
12830 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012831 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012832 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12833 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012834 return (total);
12835 case XPATH_OP_RESET:
12836 if (op->ch1 != -1)
12837 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012838 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012839 if (op->ch2 != -1)
12840 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012841 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012842 ctxt->context->node = NULL;
12843 return (total);
12844 case XPATH_OP_COLLECT:{
12845 if (op->ch1 == -1)
12846 return (0);
12847
12848 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012849 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012850
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012851 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012852 return (total);
12853 }
12854 case XPATH_OP_VALUE:
12855 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012856 xmlXPathCacheObjectCopy(ctxt->context,
12857 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012858 return (0);
12859 case XPATH_OP_SORT:
12860 if (op->ch1 != -1)
12861 total +=
12862 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12863 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012864 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012865 if ((ctxt->value != NULL)
12866 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012867 && (ctxt->value->nodesetval != NULL)
12868 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012869 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12870 return (total);
12871 default:
12872 return (xmlXPathCompOpEval(ctxt, op));
12873 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012874}
12875
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012876#ifdef XP_OPTIMIZED_FILTER_FIRST
12877static int
12878xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12879 xmlXPathStepOpPtr op, xmlNodePtr * first)
12880{
12881 int total = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012882 xmlXPathCompExprPtr comp;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012883 xmlXPathObjectPtr res;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012884 xmlXPathObjectPtr obj;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012885 xmlNodeSetPtr oldset;
12886 xmlNodePtr oldnode;
12887 xmlDocPtr oldDoc;
12888 int i;
12889
12890 CHECK_ERROR0;
12891 comp = ctxt->comp;
12892 /*
12893 * Optimization for ()[last()] selection i.e. the last elem
12894 */
12895 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12896 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12897 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12898 int f = comp->steps[op->ch2].ch1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012899
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012900 if ((f != -1) &&
12901 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12902 (comp->steps[f].value5 == NULL) &&
12903 (comp->steps[f].value == 0) &&
12904 (comp->steps[f].value4 != NULL) &&
12905 (xmlStrEqual
12906 (comp->steps[f].value4, BAD_CAST "last"))) {
12907 xmlNodePtr last = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012908
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012909 total +=
12910 xmlXPathCompOpEvalLast(ctxt,
12911 &comp->steps[op->ch1],
12912 &last);
12913 CHECK_ERROR0;
12914 /*
12915 * The nodeset should be in document order,
12916 * Keep only the last value
12917 */
12918 if ((ctxt->value != NULL) &&
12919 (ctxt->value->type == XPATH_NODESET) &&
12920 (ctxt->value->nodesetval != NULL) &&
12921 (ctxt->value->nodesetval->nodeTab != NULL) &&
12922 (ctxt->value->nodesetval->nodeNr > 1)) {
12923 ctxt->value->nodesetval->nodeTab[0] =
12924 ctxt->value->nodesetval->nodeTab[ctxt->
12925 value->
12926 nodesetval->
12927 nodeNr -
12928 1];
12929 ctxt->value->nodesetval->nodeNr = 1;
12930 *first = *(ctxt->value->nodesetval->nodeTab);
12931 }
12932 return (total);
12933 }
12934 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012935
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012936 if (op->ch1 != -1)
12937 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12938 CHECK_ERROR0;
12939 if (op->ch2 == -1)
12940 return (total);
12941 if (ctxt->value == NULL)
12942 return (total);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012943
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012944#ifdef LIBXML_XPTR_ENABLED
12945 oldnode = ctxt->context->node;
12946 /*
12947 * Hum are we filtering the result of an XPointer expression
12948 */
12949 if (ctxt->value->type == XPATH_LOCATIONSET) {
12950 xmlXPathObjectPtr tmp = NULL;
12951 xmlLocationSetPtr newlocset = NULL;
12952 xmlLocationSetPtr oldlocset;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012953
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012954 /*
12955 * Extract the old locset, and then evaluate the result of the
12956 * expression for all the element in the locset. use it to grow
12957 * up a new locset.
12958 */
12959 CHECK_TYPE0(XPATH_LOCATIONSET);
12960 obj = valuePop(ctxt);
12961 oldlocset = obj->user;
12962 ctxt->context->node = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012963
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012964 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12965 ctxt->context->contextSize = 0;
12966 ctxt->context->proximityPosition = 0;
12967 if (op->ch2 != -1)
12968 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12969 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012970 if (res != NULL) {
12971 xmlXPathReleaseObject(ctxt->context, res);
12972 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012973 valuePush(ctxt, obj);
12974 CHECK_ERROR0;
12975 return (total);
12976 }
12977 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012978
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012979 for (i = 0; i < oldlocset->locNr; i++) {
12980 /*
12981 * Run the evaluation with a node list made of a
12982 * single item in the nodelocset.
12983 */
12984 ctxt->context->node = oldlocset->locTab[i]->user;
12985 ctxt->context->contextSize = oldlocset->locNr;
12986 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012987 if (tmp == NULL) {
12988 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12989 ctxt->context->node);
12990 } else {
12991 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12992 ctxt->context->node);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012993 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012994 valuePush(ctxt, tmp);
12995 if (op->ch2 != -1)
12996 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12997 if (ctxt->error != XPATH_EXPRESSION_OK) {
12998 xmlXPathFreeObject(obj);
12999 return(0);
13000 }
13001 /*
13002 * The result of the evaluation need to be tested to
13003 * decided whether the filter succeeded or not
13004 */
13005 res = valuePop(ctxt);
13006 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13007 xmlXPtrLocationSetAdd(newlocset,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013008 xmlXPathCacheObjectCopy(ctxt->context,
13009 oldlocset->locTab[i]));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013010 }
13011 /*
13012 * Cleanup
13013 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013014 if (res != NULL) {
13015 xmlXPathReleaseObject(ctxt->context, res);
13016 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013017 if (ctxt->value == tmp) {
13018 valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013019 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013020 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013021 * REVISIT TODO: Don't create a temporary nodeset
13022 * for everly iteration.
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013023 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013024 /* OLD: xmlXPathFreeObject(res); */
13025 } else
Daniel Veillard45490ae2008-07-29 09:13:19 +000013026 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013027 ctxt->context->node = NULL;
13028 /*
13029 * Only put the first node in the result, then leave.
13030 */
13031 if (newlocset->locNr > 0) {
13032 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
13033 break;
13034 }
13035 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013036 if (tmp != NULL) {
13037 xmlXPathReleaseObject(ctxt->context, tmp);
13038 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013039 /*
13040 * The result is used as the new evaluation locset.
13041 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013042 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013043 ctxt->context->node = NULL;
13044 ctxt->context->contextSize = -1;
13045 ctxt->context->proximityPosition = -1;
13046 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13047 ctxt->context->node = oldnode;
13048 return (total);
13049 }
13050#endif /* LIBXML_XPTR_ENABLED */
Daniel Veillard45490ae2008-07-29 09:13:19 +000013051
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013052 /*
13053 * Extract the old set, and then evaluate the result of the
13054 * expression for all the element in the set. use it to grow
13055 * up a new set.
13056 */
13057 CHECK_TYPE0(XPATH_NODESET);
13058 obj = valuePop(ctxt);
13059 oldset = obj->nodesetval;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013060
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013061 oldnode = ctxt->context->node;
13062 oldDoc = ctxt->context->doc;
13063 ctxt->context->node = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013064
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013065 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13066 ctxt->context->contextSize = 0;
13067 ctxt->context->proximityPosition = 0;
13068 /* QUESTION TODO: Why was this code commented out?
13069 if (op->ch2 != -1)
13070 total +=
13071 xmlXPathCompOpEval(ctxt,
13072 &comp->steps[op->ch2]);
13073 CHECK_ERROR0;
13074 res = valuePop(ctxt);
13075 if (res != NULL)
13076 xmlXPathFreeObject(res);
13077 */
13078 valuePush(ctxt, obj);
13079 ctxt->context->node = oldnode;
13080 CHECK_ERROR0;
13081 } else {
13082 xmlNodeSetPtr newset;
13083 xmlXPathObjectPtr tmp = NULL;
13084 /*
13085 * Initialize the new set.
13086 * Also set the xpath document in case things like
13087 * key() evaluation are attempted on the predicate
Daniel Veillard45490ae2008-07-29 09:13:19 +000013088 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013089 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +000013090 /* XXX what if xmlXPathNodeSetCreate returned NULL? */
Daniel Veillard45490ae2008-07-29 09:13:19 +000013091
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013092 for (i = 0; i < oldset->nodeNr; i++) {
13093 /*
13094 * Run the evaluation with a node list made of
13095 * a single item in the nodeset.
13096 */
13097 ctxt->context->node = oldset->nodeTab[i];
13098 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13099 (oldset->nodeTab[i]->doc != NULL))
13100 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013101 if (tmp == NULL) {
13102 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13103 ctxt->context->node);
13104 } else {
13105 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13106 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013107 }
13108 valuePush(ctxt, tmp);
13109 ctxt->context->contextSize = oldset->nodeNr;
13110 ctxt->context->proximityPosition = i + 1;
13111 if (op->ch2 != -1)
13112 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13113 if (ctxt->error != XPATH_EXPRESSION_OK) {
13114 xmlXPathFreeNodeSet(newset);
13115 xmlXPathFreeObject(obj);
13116 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013117 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013118 /*
13119 * The result of the evaluation needs to be tested to
13120 * decide whether the filter succeeded or not
13121 */
13122 res = valuePop(ctxt);
13123 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13124 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013125 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013126 /*
13127 * Cleanup
13128 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013129 if (res != NULL) {
13130 xmlXPathReleaseObject(ctxt->context, res);
13131 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013132 if (ctxt->value == tmp) {
13133 valuePop(ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013134 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013135 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013136 * in order to avoid massive recreation inside this
13137 * loop.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013138 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000013139 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013140 } else
13141 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013142 ctxt->context->node = NULL;
13143 /*
13144 * Only put the first node in the result, then leave.
13145 */
13146 if (newset->nodeNr > 0) {
13147 *first = *(newset->nodeTab);
13148 break;
13149 }
13150 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013151 if (tmp != NULL) {
13152 xmlXPathReleaseObject(ctxt->context, tmp);
13153 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013154 /*
13155 * The result is used as the new evaluation set.
13156 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013157 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013158 ctxt->context->node = NULL;
13159 ctxt->context->contextSize = -1;
13160 ctxt->context->proximityPosition = -1;
13161 /* may want to move this past the '}' later */
13162 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013163 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013164 }
13165 ctxt->context->node = oldnode;
13166 return(total);
13167}
13168#endif /* XP_OPTIMIZED_FILTER_FIRST */
13169
Owen Taylor3473f882001-02-23 17:55:21 +000013170/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013171 * xmlXPathCompOpEval:
13172 * @ctxt: the XPath parser context with the compiled expression
13173 * @op: an XPath compiled operation
13174 *
13175 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000013176 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013177 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013178static int
13179xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13180{
13181 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013182 int equal, ret;
13183 xmlXPathCompExprPtr comp;
13184 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013185 xmlNodePtr bak;
13186 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000013187 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000013188 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013189
Daniel Veillard556c6682001-10-06 09:59:51 +000013190 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013191 comp = ctxt->comp;
13192 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013193 case XPATH_OP_END:
13194 return (0);
13195 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013196 bakd = ctxt->context->doc;
13197 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013198 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013199 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013200 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013201 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013202 xmlXPathBooleanFunction(ctxt, 1);
13203 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13204 return (total);
13205 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013206 ctxt->context->doc = bakd;
13207 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013208 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013209 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013210 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013211 if (ctxt->error) {
13212 xmlXPathFreeObject(arg2);
13213 return(0);
13214 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013215 xmlXPathBooleanFunction(ctxt, 1);
13216 arg1 = valuePop(ctxt);
13217 arg1->boolval &= arg2->boolval;
13218 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013219 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013220 return (total);
13221 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013222 bakd = ctxt->context->doc;
13223 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013224 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013225 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013226 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013227 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013228 xmlXPathBooleanFunction(ctxt, 1);
13229 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13230 return (total);
13231 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013232 ctxt->context->doc = bakd;
13233 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013234 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013235 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013236 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013237 if (ctxt->error) {
13238 xmlXPathFreeObject(arg2);
13239 return(0);
13240 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013241 xmlXPathBooleanFunction(ctxt, 1);
13242 arg1 = valuePop(ctxt);
13243 arg1->boolval |= arg2->boolval;
13244 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013245 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013246 return (total);
13247 case XPATH_OP_EQUAL:
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;
William M. Brack0c022ad2002-07-12 00:56:01 +000013260 if (op->value)
Daniel Veillard45490ae2008-07-29 09:13:19 +000013261 equal = xmlXPathEqualValues(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +000013262 else
13263 equal = xmlXPathNotEqualValues(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013264 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013265 return (total);
13266 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013267 bakd = ctxt->context->doc;
13268 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013269 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013270 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013271 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013272 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013273 ctxt->context->doc = bakd;
13274 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013275 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013276 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013277 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013278 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013279 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013280 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013281 return (total);
13282 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013283 bakd = ctxt->context->doc;
13284 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013285 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013286 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013287 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013288 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013289 if (op->ch2 != -1) {
13290 ctxt->context->doc = bakd;
13291 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013292 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013293 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013294 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013295 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013296 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013297 if (op->value == 0)
13298 xmlXPathSubValues(ctxt);
13299 else if (op->value == 1)
13300 xmlXPathAddValues(ctxt);
13301 else if (op->value == 2)
13302 xmlXPathValueFlipSign(ctxt);
13303 else if (op->value == 3) {
13304 CAST_TO_NUMBER;
13305 CHECK_TYPE0(XPATH_NUMBER);
13306 }
13307 return (total);
13308 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013309 bakd = ctxt->context->doc;
13310 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013311 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013312 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013313 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013314 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013315 ctxt->context->doc = bakd;
13316 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013317 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013318 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013319 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013320 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013321 if (op->value == 0)
13322 xmlXPathMultValues(ctxt);
13323 else if (op->value == 1)
13324 xmlXPathDivValues(ctxt);
13325 else if (op->value == 2)
13326 xmlXPathModValues(ctxt);
13327 return (total);
13328 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013329 bakd = ctxt->context->doc;
13330 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013331 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013332 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013333 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013334 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013335 ctxt->context->doc = bakd;
13336 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013337 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013338 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013339 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013340 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013341 CHECK_TYPE0(XPATH_NODESET);
13342 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013343
Daniel Veillardf06307e2001-07-03 10:35:50 +000013344 CHECK_TYPE0(XPATH_NODESET);
13345 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013346
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013347 if ((arg1->nodesetval == NULL) ||
13348 ((arg2->nodesetval != NULL) &&
13349 (arg2->nodesetval->nodeNr != 0)))
13350 {
13351 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13352 arg2->nodesetval);
13353 }
13354
Daniel Veillardf06307e2001-07-03 10:35:50 +000013355 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013356 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013357 return (total);
13358 case XPATH_OP_ROOT:
13359 xmlXPathRoot(ctxt);
13360 return (total);
13361 case XPATH_OP_NODE:
13362 if (op->ch1 != -1)
13363 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013364 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013365 if (op->ch2 != -1)
13366 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013367 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013368 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13369 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013370 return (total);
13371 case XPATH_OP_RESET:
13372 if (op->ch1 != -1)
13373 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013374 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013375 if (op->ch2 != -1)
13376 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013377 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013378 ctxt->context->node = NULL;
13379 return (total);
13380 case XPATH_OP_COLLECT:{
13381 if (op->ch1 == -1)
13382 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000013383
Daniel Veillardf06307e2001-07-03 10:35:50 +000013384 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013385 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013386
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013387 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013388 return (total);
13389 }
13390 case XPATH_OP_VALUE:
13391 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013392 xmlXPathCacheObjectCopy(ctxt->context,
13393 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013394 return (total);
13395 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000013396 xmlXPathObjectPtr val;
13397
Daniel Veillardf06307e2001-07-03 10:35:50 +000013398 if (op->ch1 != -1)
13399 total +=
13400 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013401 if (op->value5 == NULL) {
13402 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13403 if (val == NULL) {
13404 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13405 return(0);
13406 }
13407 valuePush(ctxt, val);
13408 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013409 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013410
Daniel Veillardf06307e2001-07-03 10:35:50 +000013411 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13412 if (URI == NULL) {
13413 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013414 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13415 (char *) op->value4, (char *)op->value5);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080013416 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013417 return (total);
13418 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013419 val = xmlXPathVariableLookupNS(ctxt->context,
13420 op->value4, URI);
13421 if (val == NULL) {
13422 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13423 return(0);
13424 }
13425 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013426 }
13427 return (total);
13428 }
13429 case XPATH_OP_FUNCTION:{
13430 xmlXPathFunction func;
13431 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000013432 int i;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013433 int frame;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013434
Daniel Veillardf5048b32011-08-18 17:10:13 +080013435 frame = xmlXPathSetFrame(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013436 if (op->ch1 != -1)
13437 total +=
13438 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013439 if (ctxt->valueNr < op->value) {
13440 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013441 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013442 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013443 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard556c6682001-10-06 09:59:51 +000013444 return (total);
13445 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080013446 for (i = 0; i < op->value; i++) {
Daniel Veillard556c6682001-10-06 09:59:51 +000013447 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13448 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013449 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013450 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013451 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard556c6682001-10-06 09:59:51 +000013452 return (total);
13453 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080013454 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013455 if (op->cache != NULL)
William M. Brackad0e67c2004-12-01 14:35:10 +000013456 XML_CAST_FPTR(func) = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013457 else {
13458 const xmlChar *URI = NULL;
13459
13460 if (op->value5 == NULL)
13461 func =
13462 xmlXPathFunctionLookup(ctxt->context,
13463 op->value4);
13464 else {
13465 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13466 if (URI == NULL) {
13467 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013468 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13469 (char *)op->value4, (char *)op->value5);
Daniel Veillardf5048b32011-08-18 17:10:13 +080013470 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080013471 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013472 return (total);
13473 }
13474 func = xmlXPathFunctionLookupNS(ctxt->context,
13475 op->value4, URI);
13476 }
13477 if (func == NULL) {
13478 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013479 "xmlXPathCompOpEval: function %s not found\n",
13480 (char *)op->value4);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013481 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013482 }
William M. Brackad0e67c2004-12-01 14:35:10 +000013483 op->cache = XML_CAST_FPTR(func);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013484 op->cacheURI = (void *) URI;
13485 }
13486 oldFunc = ctxt->context->function;
13487 oldFuncURI = ctxt->context->functionURI;
13488 ctxt->context->function = op->value4;
13489 ctxt->context->functionURI = op->cacheURI;
13490 func(ctxt, op->value);
13491 ctxt->context->function = oldFunc;
13492 ctxt->context->functionURI = oldFuncURI;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013493 xmlXPathPopFrame(ctxt, frame);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013494 return (total);
13495 }
13496 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000013497 bakd = ctxt->context->doc;
13498 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000013499 pp = ctxt->context->proximityPosition;
13500 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013501 if (op->ch1 != -1)
13502 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
William M. Brack645a9242004-11-09 12:20:42 +000013503 ctxt->context->contextSize = cs;
13504 ctxt->context->proximityPosition = pp;
Daniel Veillard088bf112002-05-14 11:03:59 +000013505 ctxt->context->node = bak;
William M. Brack645a9242004-11-09 12:20:42 +000013506 ctxt->context->doc = bakd;
Daniel Veillard556c6682001-10-06 09:59:51 +000013507 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000013508 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013509 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000013510 ctxt->context->doc = bakd;
13511 ctxt->context->node = bak;
13512 CHECK_ERROR0;
13513 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013514 return (total);
13515 case XPATH_OP_PREDICATE:
13516 case XPATH_OP_FILTER:{
13517 xmlXPathObjectPtr res;
13518 xmlXPathObjectPtr obj, tmp;
13519 xmlNodeSetPtr newset = NULL;
13520 xmlNodeSetPtr oldset;
13521 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000013522 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013523 int i;
13524
13525 /*
13526 * Optimization for ()[1] selection i.e. the first elem
13527 */
13528 if ((op->ch1 != -1) && (op->ch2 != -1) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013529#ifdef XP_OPTIMIZED_FILTER_FIRST
13530 /*
13531 * FILTER TODO: Can we assume that the inner processing
13532 * will result in an ordered list if we have an
13533 * XPATH_OP_FILTER?
13534 * What about an additional field or flag on
13535 * xmlXPathObject like @sorted ? This way we wouln'd need
13536 * to assume anything, so it would be more robust and
13537 * easier to optimize.
13538 */
13539 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13540 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13541#else
13542 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13543#endif
13544 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013545 xmlXPathObjectPtr val;
13546
13547 val = comp->steps[op->ch2].value4;
13548 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13549 (val->floatval == 1.0)) {
13550 xmlNodePtr first = NULL;
13551
13552 total +=
13553 xmlXPathCompOpEvalFirst(ctxt,
13554 &comp->steps[op->ch1],
13555 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000013556 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013557 /*
13558 * The nodeset should be in document order,
13559 * Keep only the first value
13560 */
13561 if ((ctxt->value != NULL) &&
13562 (ctxt->value->type == XPATH_NODESET) &&
13563 (ctxt->value->nodesetval != NULL) &&
13564 (ctxt->value->nodesetval->nodeNr > 1))
13565 ctxt->value->nodesetval->nodeNr = 1;
13566 return (total);
13567 }
13568 }
13569 /*
13570 * Optimization for ()[last()] selection i.e. the last elem
13571 */
13572 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13573 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13574 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13575 int f = comp->steps[op->ch2].ch1;
13576
13577 if ((f != -1) &&
13578 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13579 (comp->steps[f].value5 == NULL) &&
13580 (comp->steps[f].value == 0) &&
13581 (comp->steps[f].value4 != NULL) &&
13582 (xmlStrEqual
13583 (comp->steps[f].value4, BAD_CAST "last"))) {
13584 xmlNodePtr last = NULL;
13585
13586 total +=
13587 xmlXPathCompOpEvalLast(ctxt,
13588 &comp->steps[op->ch1],
13589 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000013590 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013591 /*
13592 * The nodeset should be in document order,
13593 * Keep only the last value
13594 */
13595 if ((ctxt->value != NULL) &&
13596 (ctxt->value->type == XPATH_NODESET) &&
13597 (ctxt->value->nodesetval != NULL) &&
13598 (ctxt->value->nodesetval->nodeTab != NULL) &&
13599 (ctxt->value->nodesetval->nodeNr > 1)) {
13600 ctxt->value->nodesetval->nodeTab[0] =
13601 ctxt->value->nodesetval->nodeTab[ctxt->
13602 value->
13603 nodesetval->
13604 nodeNr -
13605 1];
13606 ctxt->value->nodesetval->nodeNr = 1;
13607 }
13608 return (total);
13609 }
13610 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013611 /*
13612 * Process inner predicates first.
13613 * Example "index[parent::book][1]":
13614 * ...
13615 * PREDICATE <-- we are here "[1]"
13616 * PREDICATE <-- process "[parent::book]" first
13617 * SORT
13618 * COLLECT 'parent' 'name' 'node' book
13619 * NODE
13620 * ELEM Object is a number : 1
13621 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013622 if (op->ch1 != -1)
13623 total +=
13624 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013625 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013626 if (op->ch2 == -1)
13627 return (total);
13628 if (ctxt->value == NULL)
13629 return (total);
13630
13631 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013632
13633#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013634 /*
13635 * Hum are we filtering the result of an XPointer expression
13636 */
13637 if (ctxt->value->type == XPATH_LOCATIONSET) {
13638 xmlLocationSetPtr newlocset = NULL;
13639 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013640
Daniel Veillardf06307e2001-07-03 10:35:50 +000013641 /*
13642 * Extract the old locset, and then evaluate the result of the
13643 * expression for all the element in the locset. use it to grow
13644 * up a new locset.
13645 */
13646 CHECK_TYPE0(XPATH_LOCATIONSET);
13647 obj = valuePop(ctxt);
13648 oldlocset = obj->user;
13649 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013650
Daniel Veillardf06307e2001-07-03 10:35:50 +000013651 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13652 ctxt->context->contextSize = 0;
13653 ctxt->context->proximityPosition = 0;
13654 if (op->ch2 != -1)
13655 total +=
13656 xmlXPathCompOpEval(ctxt,
13657 &comp->steps[op->ch2]);
13658 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013659 if (res != NULL) {
13660 xmlXPathReleaseObject(ctxt->context, res);
13661 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013662 valuePush(ctxt, obj);
13663 CHECK_ERROR0;
13664 return (total);
13665 }
13666 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013667
Daniel Veillardf06307e2001-07-03 10:35:50 +000013668 for (i = 0; i < oldlocset->locNr; i++) {
13669 /*
13670 * Run the evaluation with a node list made of a
13671 * single item in the nodelocset.
13672 */
13673 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013674 ctxt->context->contextSize = oldlocset->locNr;
13675 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013676 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13677 ctxt->context->node);
William M. Brackf7eb7942003-12-31 07:59:17 +000013678 valuePush(ctxt, tmp);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013679
Daniel Veillardf06307e2001-07-03 10:35:50 +000013680 if (op->ch2 != -1)
13681 total +=
13682 xmlXPathCompOpEval(ctxt,
13683 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013684 if (ctxt->error != XPATH_EXPRESSION_OK) {
13685 xmlXPathFreeObject(obj);
13686 return(0);
13687 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013688
Daniel Veillardf06307e2001-07-03 10:35:50 +000013689 /*
13690 * The result of the evaluation need to be tested to
13691 * decided whether the filter succeeded or not
13692 */
13693 res = valuePop(ctxt);
13694 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13695 xmlXPtrLocationSetAdd(newlocset,
13696 xmlXPathObjectCopy
13697 (oldlocset->locTab[i]));
13698 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013699
Daniel Veillardf06307e2001-07-03 10:35:50 +000013700 /*
13701 * Cleanup
13702 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013703 if (res != NULL) {
13704 xmlXPathReleaseObject(ctxt->context, res);
13705 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013706 if (ctxt->value == tmp) {
13707 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013708 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013709 }
13710
13711 ctxt->context->node = NULL;
13712 }
13713
13714 /*
13715 * The result is used as the new evaluation locset.
13716 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013717 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013718 ctxt->context->node = NULL;
13719 ctxt->context->contextSize = -1;
13720 ctxt->context->proximityPosition = -1;
13721 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13722 ctxt->context->node = oldnode;
13723 return (total);
13724 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013725#endif /* LIBXML_XPTR_ENABLED */
13726
Daniel Veillardf06307e2001-07-03 10:35:50 +000013727 /*
13728 * Extract the old set, and then evaluate the result of the
13729 * expression for all the element in the set. use it to grow
13730 * up a new set.
13731 */
13732 CHECK_TYPE0(XPATH_NODESET);
13733 obj = valuePop(ctxt);
13734 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000013735
Daniel Veillardf06307e2001-07-03 10:35:50 +000013736 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000013737 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013738 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013739
Daniel Veillardf06307e2001-07-03 10:35:50 +000013740 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13741 ctxt->context->contextSize = 0;
13742 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000013743/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000013744 if (op->ch2 != -1)
13745 total +=
13746 xmlXPathCompOpEval(ctxt,
13747 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013748 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013749 res = valuePop(ctxt);
13750 if (res != NULL)
13751 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000013752*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000013753 valuePush(ctxt, obj);
13754 ctxt->context->node = oldnode;
13755 CHECK_ERROR0;
13756 } else {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013757 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013758 /*
13759 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000013760 * Also set the xpath document in case things like
13761 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000013762 */
13763 newset = xmlXPathNodeSetCreate(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013764 /*
13765 * SPEC XPath 1.0:
13766 * "For each node in the node-set to be filtered, the
13767 * PredicateExpr is evaluated with that node as the
13768 * context node, with the number of nodes in the
13769 * node-set as the context size, and with the proximity
13770 * position of the node in the node-set with respect to
13771 * the axis as the context position;"
13772 * @oldset is the node-set" to be filtered.
13773 *
13774 * SPEC XPath 1.0:
13775 * "only predicates change the context position and
13776 * context size (see [2.4 Predicates])."
13777 * Example:
13778 * node-set context pos
13779 * nA 1
13780 * nB 2
13781 * nC 3
13782 * After applying predicate [position() > 1] :
13783 * node-set context pos
13784 * nB 1
13785 * nC 2
13786 *
13787 * removed the first node in the node-set, then
Daniel Veillard45490ae2008-07-29 09:13:19 +000013788 * the context position of the
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013789 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013790 for (i = 0; i < oldset->nodeNr; i++) {
13791 /*
13792 * Run the evaluation with a node list made of
13793 * a single item in the nodeset.
13794 */
13795 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000013796 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13797 (oldset->nodeTab[i]->doc != NULL))
13798 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013799 if (tmp == NULL) {
13800 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13801 ctxt->context->node);
13802 } else {
13803 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13804 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013805 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013806 valuePush(ctxt, tmp);
13807 ctxt->context->contextSize = oldset->nodeNr;
13808 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013809 /*
13810 * Evaluate the predicate against the context node.
13811 * Can/should we optimize position() predicates
13812 * here (e.g. "[1]")?
13813 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013814 if (op->ch2 != -1)
13815 total +=
13816 xmlXPathCompOpEval(ctxt,
13817 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013818 if (ctxt->error != XPATH_EXPRESSION_OK) {
13819 xmlXPathFreeNodeSet(newset);
13820 xmlXPathFreeObject(obj);
13821 return(0);
13822 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013823
Daniel Veillardf06307e2001-07-03 10:35:50 +000013824 /*
William M. Brack08171912003-12-29 02:52:11 +000013825 * The result of the evaluation needs to be tested to
13826 * decide whether the filter succeeded or not
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013827 */
13828 /*
13829 * OPTIMIZE TODO: Can we use
13830 * xmlXPathNodeSetAdd*Unique()* instead?
13831 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013832 res = valuePop(ctxt);
13833 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13834 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13835 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013836
Daniel Veillardf06307e2001-07-03 10:35:50 +000013837 /*
13838 * Cleanup
13839 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013840 if (res != NULL) {
13841 xmlXPathReleaseObject(ctxt->context, res);
13842 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013843 if (ctxt->value == tmp) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013844 valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013845 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013846 /*
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013847 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013848 * in order to avoid massive recreation inside this
13849 * loop.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013850 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013851 } else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013852 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013853 ctxt->context->node = NULL;
13854 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013855 if (tmp != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013856 xmlXPathReleaseObject(ctxt->context, tmp);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013857 /*
13858 * The result is used as the new evaluation set.
13859 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013860 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013861 ctxt->context->node = NULL;
13862 ctxt->context->contextSize = -1;
13863 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000013864 /* may want to move this past the '}' later */
13865 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013866 valuePush(ctxt,
13867 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013868 }
13869 ctxt->context->node = oldnode;
13870 return (total);
13871 }
13872 case XPATH_OP_SORT:
13873 if (op->ch1 != -1)
13874 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013875 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013876 if ((ctxt->value != NULL) &&
13877 (ctxt->value->type == XPATH_NODESET) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013878 (ctxt->value->nodesetval != NULL) &&
13879 (ctxt->value->nodesetval->nodeNr > 1))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013880 {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013881 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013882 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013883 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013884#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013885 case XPATH_OP_RANGETO:{
13886 xmlXPathObjectPtr range;
13887 xmlXPathObjectPtr res, obj;
13888 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000013889 xmlLocationSetPtr newlocset = NULL;
13890 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013891 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000013892 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013893
Daniel Veillardf06307e2001-07-03 10:35:50 +000013894 if (op->ch1 != -1)
13895 total +=
13896 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13897 if (op->ch2 == -1)
13898 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013899
William M. Brack08171912003-12-29 02:52:11 +000013900 if (ctxt->value->type == XPATH_LOCATIONSET) {
13901 /*
13902 * Extract the old locset, and then evaluate the result of the
13903 * expression for all the element in the locset. use it to grow
13904 * up a new locset.
13905 */
13906 CHECK_TYPE0(XPATH_LOCATIONSET);
13907 obj = valuePop(ctxt);
13908 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013909
William M. Brack08171912003-12-29 02:52:11 +000013910 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000013911 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000013912 ctxt->context->contextSize = 0;
13913 ctxt->context->proximityPosition = 0;
13914 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13915 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013916 if (res != NULL) {
13917 xmlXPathReleaseObject(ctxt->context, res);
13918 }
William M. Brack08171912003-12-29 02:52:11 +000013919 valuePush(ctxt, obj);
13920 CHECK_ERROR0;
13921 return (total);
13922 }
13923 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013924
William M. Brack08171912003-12-29 02:52:11 +000013925 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013926 /*
William M. Brack08171912003-12-29 02:52:11 +000013927 * Run the evaluation with a node list made of a
13928 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000013929 */
William M. Brackf7eb7942003-12-31 07:59:17 +000013930 ctxt->context->node = oldlocset->locTab[i]->user;
13931 ctxt->context->contextSize = oldlocset->locNr;
13932 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013933 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13934 ctxt->context->node);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013935 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013936
Daniel Veillardf06307e2001-07-03 10:35:50 +000013937 if (op->ch2 != -1)
13938 total +=
13939 xmlXPathCompOpEval(ctxt,
13940 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013941 if (ctxt->error != XPATH_EXPRESSION_OK) {
13942 xmlXPathFreeObject(obj);
13943 return(0);
13944 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013945
Daniel Veillardf06307e2001-07-03 10:35:50 +000013946 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000013947 if (res->type == XPATH_LOCATIONSET) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000013948 xmlLocationSetPtr rloc =
William M. Brack72ee48d2003-12-30 08:30:19 +000013949 (xmlLocationSetPtr)res->user;
13950 for (j=0; j<rloc->locNr; j++) {
13951 range = xmlXPtrNewRange(
13952 oldlocset->locTab[i]->user,
13953 oldlocset->locTab[i]->index,
13954 rloc->locTab[j]->user2,
13955 rloc->locTab[j]->index2);
13956 if (range != NULL) {
13957 xmlXPtrLocationSetAdd(newlocset, range);
13958 }
13959 }
13960 } else {
13961 range = xmlXPtrNewRangeNodeObject(
13962 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13963 if (range != NULL) {
13964 xmlXPtrLocationSetAdd(newlocset,range);
13965 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013966 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013967
Daniel Veillardf06307e2001-07-03 10:35:50 +000013968 /*
13969 * Cleanup
13970 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013971 if (res != NULL) {
13972 xmlXPathReleaseObject(ctxt->context, res);
13973 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013974 if (ctxt->value == tmp) {
13975 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013976 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013977 }
13978
13979 ctxt->context->node = NULL;
13980 }
William M. Brack72ee48d2003-12-30 08:30:19 +000013981 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000013982 CHECK_TYPE0(XPATH_NODESET);
13983 obj = valuePop(ctxt);
13984 oldset = obj->nodesetval;
13985 ctxt->context->node = NULL;
13986
13987 newlocset = xmlXPtrLocationSetCreate(NULL);
13988
13989 if (oldset != NULL) {
13990 for (i = 0; i < oldset->nodeNr; i++) {
13991 /*
13992 * Run the evaluation with a node list made of a single item
13993 * in the nodeset.
13994 */
13995 ctxt->context->node = oldset->nodeTab[i];
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013996 /*
13997 * OPTIMIZE TODO: Avoid recreation for every iteration.
13998 */
13999 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14000 ctxt->context->node);
William M. Brack08171912003-12-29 02:52:11 +000014001 valuePush(ctxt, tmp);
14002
14003 if (op->ch2 != -1)
14004 total +=
14005 xmlXPathCompOpEval(ctxt,
14006 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000014007 if (ctxt->error != XPATH_EXPRESSION_OK) {
14008 xmlXPathFreeObject(obj);
14009 return(0);
14010 }
William M. Brack08171912003-12-29 02:52:11 +000014011
William M. Brack08171912003-12-29 02:52:11 +000014012 res = valuePop(ctxt);
14013 range =
14014 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
14015 res);
14016 if (range != NULL) {
14017 xmlXPtrLocationSetAdd(newlocset, range);
14018 }
14019
14020 /*
14021 * Cleanup
14022 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014023 if (res != NULL) {
14024 xmlXPathReleaseObject(ctxt->context, res);
14025 }
William M. Brack08171912003-12-29 02:52:11 +000014026 if (ctxt->value == tmp) {
14027 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014028 xmlXPathReleaseObject(ctxt->context, res);
William M. Brack08171912003-12-29 02:52:11 +000014029 }
14030
14031 ctxt->context->node = NULL;
14032 }
14033 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014034 }
14035
14036 /*
14037 * The result is used as the new evaluation set.
14038 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014039 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000014040 ctxt->context->node = NULL;
14041 ctxt->context->contextSize = -1;
14042 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000014043 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000014044 return (total);
14045 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014046#endif /* LIBXML_XPTR_ENABLED */
14047 }
14048 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000014049 "XPath: unknown precompiled operation %d\n", op->op);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080014050 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf06307e2001-07-03 10:35:50 +000014051 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014052}
14053
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014054/**
14055 * xmlXPathCompOpEvalToBoolean:
14056 * @ctxt: the XPath parser context
14057 *
14058 * Evaluates if the expression evaluates to true.
14059 *
14060 * Returns 1 if true, 0 if false and -1 on API or internal errors.
14061 */
14062static int
14063xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014064 xmlXPathStepOpPtr op,
14065 int isPredicate)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014066{
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014067 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014068
14069start:
14070 /* comp = ctxt->comp; */
14071 switch (op->op) {
14072 case XPATH_OP_END:
14073 return (0);
14074 case XPATH_OP_VALUE:
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014075 resObj = (xmlXPathObjectPtr) op->value4;
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000014076 if (isPredicate)
14077 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14078 return(xmlXPathCastToBoolean(resObj));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014079 case XPATH_OP_SORT:
14080 /*
14081 * We don't need sorting for boolean results. Skip this one.
14082 */
14083 if (op->ch1 != -1) {
14084 op = &ctxt->comp->steps[op->ch1];
14085 goto start;
14086 }
14087 return(0);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014088 case XPATH_OP_COLLECT:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014089 if (op->ch1 == -1)
14090 return(0);
14091
14092 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14093 if (ctxt->error != XPATH_EXPRESSION_OK)
14094 return(-1);
14095
14096 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14097 if (ctxt->error != XPATH_EXPRESSION_OK)
14098 return(-1);
14099
14100 resObj = valuePop(ctxt);
14101 if (resObj == NULL)
14102 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014103 break;
14104 default:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014105 /*
14106 * Fallback to call xmlXPathCompOpEval().
14107 */
14108 xmlXPathCompOpEval(ctxt, op);
14109 if (ctxt->error != XPATH_EXPRESSION_OK)
14110 return(-1);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014111
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014112 resObj = valuePop(ctxt);
14113 if (resObj == NULL)
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000014114 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014115 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014116 }
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014117
14118 if (resObj) {
14119 int res;
14120
14121 if (resObj->type == XPATH_BOOLEAN) {
14122 res = resObj->boolval;
14123 } else if (isPredicate) {
14124 /*
14125 * For predicates a result of type "number" is handled
14126 * differently:
14127 * SPEC XPath 1.0:
14128 * "If the result is a number, the result will be converted
14129 * to true if the number is equal to the context position
14130 * and will be converted to false otherwise;"
14131 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000014132 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014133 } else {
14134 res = xmlXPathCastToBoolean(resObj);
14135 }
14136 xmlXPathReleaseObject(ctxt->context, resObj);
14137 return(res);
14138 }
14139
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014140 return(0);
14141}
14142
Daniel Veillard56de87e2005-02-16 00:22:29 +000014143#ifdef XPATH_STREAMING
14144/**
14145 * xmlXPathRunStreamEval:
14146 * @ctxt: the XPath parser context with the compiled expression
14147 *
14148 * Evaluate the Precompiled Streamable XPath expression in the given context.
14149 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014150static int
14151xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14152 xmlXPathObjectPtr *resultSeq, int toBool)
14153{
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014154 int max_depth, min_depth;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014155 int from_root;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014156 int ret, depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014157 int eval_all_nodes;
William M. Brack12d37ab2005-02-21 13:54:07 +000014158 xmlNodePtr cur = NULL, limit = NULL;
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014159 xmlStreamCtxtPtr patstream = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014160
14161 int nb_nodes = 0;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014162
14163 if ((ctxt == NULL) || (comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014164 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014165 max_depth = xmlPatternMaxDepth(comp);
14166 if (max_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014167 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014168 if (max_depth == -2)
14169 max_depth = 10000;
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014170 min_depth = xmlPatternMinDepth(comp);
14171 if (min_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014172 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014173 from_root = xmlPatternFromRoot(comp);
14174 if (from_root < 0)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014175 return(-1);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014176#if 0
14177 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14178#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000014179
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014180 if (! toBool) {
14181 if (resultSeq == NULL)
14182 return(-1);
14183 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14184 if (*resultSeq == NULL)
14185 return(-1);
14186 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014187
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014188 /*
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014189 * handle the special cases of "/" amd "." being matched
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014190 */
14191 if (min_depth == 0) {
14192 if (from_root) {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014193 /* Select "/" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014194 if (toBool)
14195 return(1);
14196 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14197 (xmlNodePtr) ctxt->doc);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014198 } else {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014199 /* Select "self::node()" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014200 if (toBool)
14201 return(1);
14202 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014203 }
14204 }
14205 if (max_depth == 0) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014206 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014207 }
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014208
Daniel Veillard56de87e2005-02-16 00:22:29 +000014209 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000014210 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014211 } else if (ctxt->node != NULL) {
14212 switch (ctxt->node->type) {
14213 case XML_ELEMENT_NODE:
14214 case XML_DOCUMENT_NODE:
14215 case XML_DOCUMENT_FRAG_NODE:
14216 case XML_HTML_DOCUMENT_NODE:
14217#ifdef LIBXML_DOCB_ENABLED
14218 case XML_DOCB_DOCUMENT_NODE:
14219#endif
14220 cur = ctxt->node;
14221 break;
14222 case XML_ATTRIBUTE_NODE:
14223 case XML_TEXT_NODE:
14224 case XML_CDATA_SECTION_NODE:
14225 case XML_ENTITY_REF_NODE:
14226 case XML_ENTITY_NODE:
14227 case XML_PI_NODE:
14228 case XML_COMMENT_NODE:
14229 case XML_NOTATION_NODE:
14230 case XML_DTD_NODE:
14231 case XML_DOCUMENT_TYPE_NODE:
14232 case XML_ELEMENT_DECL:
14233 case XML_ATTRIBUTE_DECL:
14234 case XML_ENTITY_DECL:
14235 case XML_NAMESPACE_DECL:
14236 case XML_XINCLUDE_START:
14237 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000014238 break;
14239 }
14240 limit = cur;
14241 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014242 if (cur == NULL) {
14243 return(0);
14244 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014245
14246 patstream = xmlPatternGetStreamCtxt(comp);
14247 if (patstream == NULL) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014248 /*
14249 * QUESTION TODO: Is this an error?
14250 */
14251 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014252 }
14253
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014254 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014255
Daniel Veillard56de87e2005-02-16 00:22:29 +000014256 if (from_root) {
14257 ret = xmlStreamPush(patstream, NULL, NULL);
14258 if (ret < 0) {
14259 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014260 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014261 goto return_1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014262 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014263 }
14264 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014265 depth = 0;
14266 goto scan_children;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014267next_node:
Daniel Veillardd3ff7ef2006-02-27 19:43:17 +000014268 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014269 nb_nodes++;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014270
14271 switch (cur->type) {
14272 case XML_ELEMENT_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014273 case XML_TEXT_NODE:
14274 case XML_CDATA_SECTION_NODE:
14275 case XML_COMMENT_NODE:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014276 case XML_PI_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014277 if (cur->type == XML_ELEMENT_NODE) {
14278 ret = xmlStreamPush(patstream, cur->name,
Daniel Veillard56de87e2005-02-16 00:22:29 +000014279 (cur->ns ? cur->ns->href : NULL));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014280 } else if (eval_all_nodes)
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014281 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14282 else
14283 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014284
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014285 if (ret < 0) {
14286 /* NOP. */
14287 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014288 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014289 goto return_1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014290 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014291 }
14292 if ((cur->children == NULL) || (depth >= max_depth)) {
14293 ret = xmlStreamPop(patstream);
14294 while (cur->next != NULL) {
14295 cur = cur->next;
14296 if ((cur->type != XML_ENTITY_DECL) &&
14297 (cur->type != XML_DTD_NODE))
14298 goto next_node;
14299 }
14300 }
14301 default:
14302 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014303 }
14304
Daniel Veillard56de87e2005-02-16 00:22:29 +000014305scan_children:
14306 if ((cur->children != NULL) && (depth < max_depth)) {
14307 /*
Daniel Veillard45490ae2008-07-29 09:13:19 +000014308 * Do not descend on entities declarations
Daniel Veillard56de87e2005-02-16 00:22:29 +000014309 */
14310 if (cur->children->type != XML_ENTITY_DECL) {
14311 cur = cur->children;
14312 depth++;
14313 /*
14314 * Skip DTDs
14315 */
14316 if (cur->type != XML_DTD_NODE)
14317 continue;
14318 }
14319 }
14320
14321 if (cur == limit)
14322 break;
14323
14324 while (cur->next != NULL) {
14325 cur = cur->next;
14326 if ((cur->type != XML_ENTITY_DECL) &&
14327 (cur->type != XML_DTD_NODE))
14328 goto next_node;
14329 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014330
Daniel Veillard56de87e2005-02-16 00:22:29 +000014331 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014332 cur = cur->parent;
14333 depth--;
14334 if ((cur == NULL) || (cur == limit))
14335 goto done;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014336 if (cur->type == XML_ELEMENT_NODE) {
14337 ret = xmlStreamPop(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014338 } else if ((eval_all_nodes) &&
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014339 ((cur->type == XML_TEXT_NODE) ||
14340 (cur->type == XML_CDATA_SECTION_NODE) ||
14341 (cur->type == XML_COMMENT_NODE) ||
14342 (cur->type == XML_PI_NODE)))
14343 {
14344 ret = xmlStreamPop(patstream);
14345 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014346 if (cur->next != NULL) {
14347 cur = cur->next;
14348 break;
14349 }
14350 } while (cur != NULL);
14351
14352 } while ((cur != NULL) && (depth >= 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014353
Daniel Veillard56de87e2005-02-16 00:22:29 +000014354done:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014355
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014356#if 0
14357 printf("stream eval: checked %d nodes selected %d\n",
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014358 nb_nodes, retObj->nodesetval->nodeNr);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014359#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014360
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014361 if (patstream)
14362 xmlFreeStreamCtxt(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014363 return(0);
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014364
14365return_1:
14366 if (patstream)
14367 xmlFreeStreamCtxt(patstream);
14368 return(1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014369}
14370#endif /* XPATH_STREAMING */
14371
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014372/**
14373 * xmlXPathRunEval:
14374 * @ctxt: the XPath parser context with the compiled expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014375 * @toBool: evaluate to a boolean result
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014376 *
14377 * Evaluate the Precompiled XPath expression in the given context.
14378 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014379static int
14380xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14381{
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014382 xmlXPathCompExprPtr comp;
14383
14384 if ((ctxt == NULL) || (ctxt->comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014385 return(-1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014386
14387 if (ctxt->valueTab == NULL) {
14388 /* Allocate the value stack */
Daniel Veillard45490ae2008-07-29 09:13:19 +000014389 ctxt->valueTab = (xmlXPathObjectPtr *)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014390 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14391 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000014392 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014393 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014394 }
14395 ctxt->valueNr = 0;
14396 ctxt->valueMax = 10;
14397 ctxt->value = NULL;
Daniel Veillardf5048b32011-08-18 17:10:13 +080014398 ctxt->valueFrame = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014399 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014400#ifdef XPATH_STREAMING
14401 if (ctxt->comp->stream) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014402 int res;
14403
14404 if (toBool) {
14405 /*
14406 * Evaluation to boolean result.
14407 */
14408 res = xmlXPathRunStreamEval(ctxt->context,
14409 ctxt->comp->stream, NULL, 1);
14410 if (res != -1)
14411 return(res);
14412 } else {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014413 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014414
14415 /*
14416 * Evaluation to a sequence.
14417 */
14418 res = xmlXPathRunStreamEval(ctxt->context,
14419 ctxt->comp->stream, &resObj, 0);
14420
14421 if ((res != -1) && (resObj != NULL)) {
14422 valuePush(ctxt, resObj);
14423 return(0);
14424 }
14425 if (resObj != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +000014426 xmlXPathReleaseObject(ctxt->context, resObj);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014427 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014428 /*
14429 * QUESTION TODO: This falls back to normal XPath evaluation
14430 * if res == -1. Is this intended?
14431 */
Daniel Veillard56de87e2005-02-16 00:22:29 +000014432 }
14433#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014434 comp = ctxt->comp;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014435 if (comp->last < 0) {
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014436 xmlGenericError(xmlGenericErrorContext,
14437 "xmlXPathRunEval: last is less than zero\n");
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014438 return(-1);
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014439 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014440 if (toBool)
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014441 return(xmlXPathCompOpEvalToBoolean(ctxt,
14442 &comp->steps[comp->last], 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014443 else
14444 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14445
14446 return(0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014447}
14448
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014449/************************************************************************
14450 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +000014451 * Public interfaces *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014452 * *
14453 ************************************************************************/
14454
14455/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014456 * xmlXPathEvalPredicate:
14457 * @ctxt: the XPath context
14458 * @res: the Predicate Expression evaluation result
14459 *
14460 * Evaluate a predicate result for the current node.
14461 * A PredicateExpr is evaluated by evaluating the Expr and converting
14462 * the result to a boolean. If the result is a number, the result will
14463 * be converted to true if the number is equal to the position of the
14464 * context node in the context node list (as returned by the position
14465 * function) and will be converted to false otherwise; if the result
14466 * is not a number, then the result will be converted as if by a call
Daniel Veillard45490ae2008-07-29 09:13:19 +000014467 * to the boolean function.
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014468 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014469 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014470 */
14471int
14472xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014473 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014474 switch (res->type) {
14475 case XPATH_BOOLEAN:
14476 return(res->boolval);
14477 case XPATH_NUMBER:
14478 return(res->floatval == ctxt->proximityPosition);
14479 case XPATH_NODESET:
14480 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000014481 if (res->nodesetval == NULL)
14482 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014483 return(res->nodesetval->nodeNr != 0);
14484 case XPATH_STRING:
14485 return((res->stringval != NULL) &&
14486 (xmlStrlen(res->stringval) != 0));
14487 default:
14488 STRANGE
14489 }
14490 return(0);
14491}
14492
14493/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014494 * xmlXPathEvaluatePredicateResult:
14495 * @ctxt: the XPath Parser context
14496 * @res: the Predicate Expression evaluation result
14497 *
14498 * Evaluate a predicate result for the current node.
14499 * A PredicateExpr is evaluated by evaluating the Expr and converting
14500 * the result to a boolean. If the result is a number, the result will
14501 * be converted to true if the number is equal to the position of the
14502 * context node in the context node list (as returned by the position
14503 * function) and will be converted to false otherwise; if the result
14504 * is not a number, then the result will be converted as if by a call
Daniel Veillard45490ae2008-07-29 09:13:19 +000014505 * to the boolean function.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014506 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014507 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014508 */
14509int
Daniel Veillard45490ae2008-07-29 09:13:19 +000014510xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014511 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014512 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014513 switch (res->type) {
14514 case XPATH_BOOLEAN:
14515 return(res->boolval);
14516 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000014517#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000014518 return((res->floatval == ctxt->context->proximityPosition) &&
14519 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000014520#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014521 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000014522#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014523 case XPATH_NODESET:
14524 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000014525 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000014526 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014527 return(res->nodesetval->nodeNr != 0);
14528 case XPATH_STRING:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014529 return((res->stringval != NULL) && (res->stringval[0] != 0));
William M. Brack08171912003-12-29 02:52:11 +000014530#ifdef LIBXML_XPTR_ENABLED
14531 case XPATH_LOCATIONSET:{
14532 xmlLocationSetPtr ptr = res->user;
14533 if (ptr == NULL)
14534 return(0);
14535 return (ptr->locNr != 0);
14536 }
14537#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014538 default:
14539 STRANGE
14540 }
14541 return(0);
14542}
14543
Daniel Veillard56de87e2005-02-16 00:22:29 +000014544#ifdef XPATH_STREAMING
14545/**
14546 * xmlXPathTryStreamCompile:
14547 * @ctxt: an XPath context
14548 * @str: the XPath expression
14549 *
14550 * Try to compile the XPath expression as a streamable subset.
14551 *
14552 * Returns the compiled expression or NULL if failed to compile.
14553 */
14554static xmlXPathCompExprPtr
14555xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14556 /*
14557 * Optimization: use streaming patterns when the XPath expression can
14558 * be compiled to a stream lookup
14559 */
14560 xmlPatternPtr stream;
14561 xmlXPathCompExprPtr comp;
14562 xmlDictPtr dict = NULL;
14563 const xmlChar **namespaces = NULL;
14564 xmlNsPtr ns;
14565 int i, j;
14566
14567 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14568 (!xmlStrchr(str, '@'))) {
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014569 const xmlChar *tmp;
14570
14571 /*
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014572 * We don't try to handle expressions using the verbose axis
14573 * specifiers ("::"), just the simplied form at this point.
14574 * Additionally, if there is no list of namespaces available and
14575 * there's a ":" in the expression, indicating a prefixed QName,
14576 * then we won't try to compile either. xmlPatterncompile() needs
14577 * to have a list of namespaces at compilation time in order to
14578 * compile prefixed name tests.
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014579 */
14580 tmp = xmlStrchr(str, ':');
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014581 if ((tmp != NULL) &&
14582 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
Daniel Veillard45490ae2008-07-29 09:13:19 +000014583 return(NULL);
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014584
Daniel Veillard56de87e2005-02-16 00:22:29 +000014585 if (ctxt != NULL) {
14586 dict = ctxt->dict;
14587 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000014588 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000014589 if (namespaces == NULL) {
14590 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14591 return(NULL);
14592 }
14593 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14594 ns = ctxt->namespaces[j];
14595 namespaces[i++] = ns->href;
14596 namespaces[i++] = ns->prefix;
14597 }
14598 namespaces[i++] = NULL;
Daniel Veillard13cee4e2009-09-05 14:52:55 +020014599 namespaces[i] = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014600 }
14601 }
14602
William M. Brackea152c02005-06-09 18:12:28 +000014603 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14604 &namespaces[0]);
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014605 if (namespaces != NULL) {
14606 xmlFree((xmlChar **)namespaces);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014607 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014608 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14609 comp = xmlXPathNewCompExpr();
14610 if (comp == NULL) {
14611 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14612 return(NULL);
14613 }
14614 comp->stream = stream;
14615 comp->dict = dict;
14616 if (comp->dict)
14617 xmlDictReference(comp->dict);
14618 return(comp);
14619 }
14620 xmlFreePattern(stream);
14621 }
14622 return(NULL);
14623}
14624#endif /* XPATH_STREAMING */
14625
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014626static int
14627xmlXPathCanRewriteDosExpression(xmlChar *expr)
14628{
14629 if (expr == NULL)
14630 return(0);
14631 do {
14632 if ((*expr == '/') && (*(++expr) == '/'))
14633 return(1);
14634 } while (*expr++);
14635 return(0);
14636}
14637static void
14638xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14639{
14640 /*
14641 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14642 * internal representation.
14643 */
14644 if (op->ch1 != -1) {
14645 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +000014646 ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014647 ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
14648 ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
14649 {
14650 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014651 * This is a "child::foo"
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014652 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000014653 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014654
14655 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +000014656 (prevop->ch1 != -1) &&
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014657 ((xmlXPathAxisVal) prevop->value ==
14658 AXIS_DESCENDANT_OR_SELF) &&
14659 (prevop->ch2 == -1) &&
14660 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014661 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
14662 (comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
Daniel Veillard45490ae2008-07-29 09:13:19 +000014663 {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014664 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014665 * This is a "/descendant-or-self::node()" without predicates.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014666 * Eliminate it.
14667 */
14668 op->ch1 = prevop->ch1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014669 op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014670 }
14671 }
14672 if (op->ch1 != -1)
14673 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
14674 }
14675 if (op->ch2 != -1)
14676 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
14677}
14678
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014679/**
Daniel Veillard4773df22004-01-23 13:15:13 +000014680 * xmlXPathCtxtCompile:
14681 * @ctxt: an XPath context
14682 * @str: the XPath expression
14683 *
14684 * Compile an XPath expression
14685 *
14686 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14687 * the caller has to free the object.
14688 */
14689xmlXPathCompExprPtr
14690xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14691 xmlXPathParserContextPtr pctxt;
14692 xmlXPathCompExprPtr comp;
14693
Daniel Veillard56de87e2005-02-16 00:22:29 +000014694#ifdef XPATH_STREAMING
14695 comp = xmlXPathTryStreamCompile(ctxt, str);
14696 if (comp != NULL)
14697 return(comp);
14698#endif
14699
Daniel Veillard4773df22004-01-23 13:15:13 +000014700 xmlXPathInit();
14701
14702 pctxt = xmlXPathNewParserContext(str, ctxt);
William M. Brack11be2d02007-01-24 19:17:19 +000014703 if (pctxt == NULL)
14704 return NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014705 xmlXPathCompileExpr(pctxt, 1);
Daniel Veillard4773df22004-01-23 13:15:13 +000014706
14707 if( pctxt->error != XPATH_EXPRESSION_OK )
14708 {
14709 xmlXPathFreeParserContext(pctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000014710 return(NULL);
Daniel Veillard4773df22004-01-23 13:15:13 +000014711 }
14712
14713 if (*pctxt->cur != 0) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014714 /*
Daniel Veillard4773df22004-01-23 13:15:13 +000014715 * aleksey: in some cases this line prints *second* error message
14716 * (see bug #78858) and probably this should be fixed.
14717 * However, we are not sure that all error messages are printed
14718 * out in other places. It's not critical so we leave it as-is for now
14719 */
14720 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14721 comp = NULL;
14722 } else {
14723 comp = pctxt->comp;
14724 pctxt->comp = NULL;
14725 }
14726 xmlXPathFreeParserContext(pctxt);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014727
Daniel Veillard4773df22004-01-23 13:15:13 +000014728 if (comp != NULL) {
14729 comp->expr = xmlStrdup(str);
14730#ifdef DEBUG_EVAL_COUNTS
14731 comp->string = xmlStrdup(str);
14732 comp->nb = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014733#endif
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014734 if ((comp->expr != NULL) &&
14735 (comp->nbStep > 2) &&
14736 (comp->last >= 0) &&
Kasimier T. Buchcik7cb3fa92006-06-06 15:27:46 +000014737 (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
14738 {
14739 xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014740 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014741 }
Daniel Veillard4773df22004-01-23 13:15:13 +000014742 return(comp);
14743}
14744
14745/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014746 * xmlXPathCompile:
14747 * @str: the XPath expression
14748 *
14749 * Compile an XPath expression
14750 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000014751 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014752 * the caller has to free the object.
14753 */
14754xmlXPathCompExprPtr
14755xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000014756 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014757}
14758
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014759/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014760 * xmlXPathCompiledEvalInternal:
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014761 * @comp: the compiled XPath expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014762 * @ctxt: the XPath context
14763 * @resObj: the resulting XPath object or NULL
14764 * @toBool: 1 if only a boolean result is requested
Owen Taylor3473f882001-02-23 17:55:21 +000014765 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014766 * Evaluate the Precompiled XPath expression in the given context.
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014767 * The caller has to free @resObj.
Owen Taylor3473f882001-02-23 17:55:21 +000014768 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014769 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000014770 * the caller has to free the object.
14771 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014772static int
14773xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14774 xmlXPathContextPtr ctxt,
14775 xmlXPathObjectPtr *resObj,
14776 int toBool)
14777{
Daniel Veillard45490ae2008-07-29 09:13:19 +000014778 xmlXPathParserContextPtr pctxt;
Daniel Veillard81463942001-10-16 12:34:39 +000014779#ifndef LIBXML_THREAD_ENABLED
14780 static int reentance = 0;
14781#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014782 int res;
Owen Taylor3473f882001-02-23 17:55:21 +000014783
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014784 CHECK_CTXT_NEG(ctxt)
William M. Brackf13f77f2004-11-12 16:03:48 +000014785
14786 if (comp == NULL)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014787 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +000014788 xmlXPathInit();
14789
Daniel Veillard81463942001-10-16 12:34:39 +000014790#ifndef LIBXML_THREAD_ENABLED
14791 reentance++;
14792 if (reentance > 1)
14793 xmlXPathDisableOptimizer = 1;
14794#endif
14795
Daniel Veillardf06307e2001-07-03 10:35:50 +000014796#ifdef DEBUG_EVAL_COUNTS
14797 comp->nb++;
14798 if ((comp->string != NULL) && (comp->nb > 100)) {
14799 fprintf(stderr, "100 x %s\n", comp->string);
14800 comp->nb = 0;
14801 }
14802#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014803 pctxt = xmlXPathCompParserContext(comp, ctxt);
14804 res = xmlXPathRunEval(pctxt, toBool);
Owen Taylor3473f882001-02-23 17:55:21 +000014805
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014806 if (resObj) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014807 if (pctxt->value == NULL) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014808 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014809 "xmlXPathCompiledEval: evaluation failed\n");
Daniel Veillard45490ae2008-07-29 09:13:19 +000014810 *resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014811 } else {
14812 *resObj = valuePop(pctxt);
14813 }
Owen Taylor3473f882001-02-23 17:55:21 +000014814 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014815
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014816 /*
14817 * Pop all remaining objects from the stack.
14818 */
14819 if (pctxt->valueNr > 0) {
14820 xmlXPathObjectPtr tmp;
14821 int stack = 0;
14822
14823 do {
14824 tmp = valuePop(pctxt);
14825 if (tmp != NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014826 stack++;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014827 xmlXPathReleaseObject(ctxt, tmp);
14828 }
14829 } while (tmp != NULL);
14830 if ((stack != 0) &&
14831 ((toBool) || ((resObj) && (*resObj))))
14832 {
14833 xmlGenericError(xmlGenericErrorContext,
14834 "xmlXPathCompiledEval: %d objects left on the stack.\n",
14835 stack);
14836 }
Owen Taylor3473f882001-02-23 17:55:21 +000014837 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014838
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014839 if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14840 xmlXPathFreeObject(*resObj);
14841 *resObj = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014842 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014843 pctxt->comp = NULL;
14844 xmlXPathFreeParserContext(pctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000014845#ifndef LIBXML_THREAD_ENABLED
14846 reentance--;
14847#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014848
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014849 return(res);
14850}
14851
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014852/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014853 * xmlXPathCompiledEval:
14854 * @comp: the compiled XPath expression
14855 * @ctx: the XPath context
14856 *
14857 * Evaluate the Precompiled XPath expression in the given context.
14858 *
14859 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14860 * the caller has to free the object.
14861 */
14862xmlXPathObjectPtr
14863xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14864{
14865 xmlXPathObjectPtr res = NULL;
14866
14867 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14868 return(res);
14869}
14870
14871/**
14872 * xmlXPathCompiledEvalToBoolean:
14873 * @comp: the compiled XPath expression
14874 * @ctxt: the XPath context
14875 *
14876 * Applies the XPath boolean() function on the result of the given
14877 * compiled expression.
14878 *
14879 * Returns 1 if the expression evaluated to true, 0 if to false and
14880 * -1 in API and internal errors.
14881 */
14882int
14883xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14884 xmlXPathContextPtr ctxt)
14885{
14886 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14887}
14888
14889/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014890 * xmlXPathEvalExpr:
14891 * @ctxt: the XPath Parser context
14892 *
14893 * Parse and evaluate an XPath expression in the given context,
14894 * then push the result on the context stack
14895 */
14896void
14897xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014898#ifdef XPATH_STREAMING
14899 xmlXPathCompExprPtr comp;
14900#endif
14901
Daniel Veillarda82b1822004-11-08 16:24:57 +000014902 if (ctxt == NULL) return;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014903
Daniel Veillard56de87e2005-02-16 00:22:29 +000014904#ifdef XPATH_STREAMING
14905 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14906 if (comp != NULL) {
14907 if (ctxt->comp != NULL)
14908 xmlXPathFreeCompExpr(ctxt->comp);
14909 ctxt->comp = comp;
14910 if (ctxt->cur != NULL)
14911 while (*ctxt->cur != 0) ctxt->cur++;
14912 } else
14913#endif
14914 {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014915 xmlXPathCompileExpr(ctxt, 1);
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014916 /*
14917 * In this scenario the expression string will sit in ctxt->base.
14918 */
14919 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
14920 (ctxt->comp != NULL) &&
14921 (ctxt->base != NULL) &&
Kasimier T. Buchcik7cb3fa92006-06-06 15:27:46 +000014922 (ctxt->comp->nbStep > 2) &&
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014923 (ctxt->comp->last >= 0) &&
14924 (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014925 {
14926 xmlXPathRewriteDOSExpression(ctxt->comp,
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014927 &ctxt->comp->steps[ctxt->comp->last]);
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014928 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014929 }
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000014930 CHECK_ERROR;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014931 xmlXPathRunEval(ctxt, 0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014932}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014933
14934/**
14935 * xmlXPathEval:
14936 * @str: the XPath expression
14937 * @ctx: the XPath context
14938 *
14939 * Evaluate the XPath Location Path in the given context.
14940 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014941 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014942 * the caller has to free the object.
14943 */
14944xmlXPathObjectPtr
14945xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14946 xmlXPathParserContextPtr ctxt;
14947 xmlXPathObjectPtr res, tmp, init = NULL;
14948 int stack = 0;
14949
William M. Brackf13f77f2004-11-12 16:03:48 +000014950 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014951
William M. Brackf13f77f2004-11-12 16:03:48 +000014952 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014953
14954 ctxt = xmlXPathNewParserContext(str, ctx);
William M. Brack11be2d02007-01-24 19:17:19 +000014955 if (ctxt == NULL)
14956 return NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014957 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014958
14959 if (ctxt->value == NULL) {
14960 xmlGenericError(xmlGenericErrorContext,
14961 "xmlXPathEval: evaluation failed\n");
14962 res = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014963 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
Daniel Veillard56de87e2005-02-16 00:22:29 +000014964#ifdef XPATH_STREAMING
14965 && (ctxt->comp->stream == NULL)
14966#endif
14967 ) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014968 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14969 res = NULL;
14970 } else {
14971 res = valuePop(ctxt);
14972 }
14973
14974 do {
14975 tmp = valuePop(ctxt);
14976 if (tmp != NULL) {
14977 if (tmp != init)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014978 stack++;
14979 xmlXPathReleaseObject(ctx, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014980 }
14981 } while (tmp != NULL);
14982 if ((stack != 0) && (res != NULL)) {
14983 xmlGenericError(xmlGenericErrorContext,
14984 "xmlXPathEval: %d object left on the stack\n",
14985 stack);
14986 }
14987 if (ctxt->error != XPATH_EXPRESSION_OK) {
14988 xmlXPathFreeObject(res);
14989 res = NULL;
14990 }
14991
Owen Taylor3473f882001-02-23 17:55:21 +000014992 xmlXPathFreeParserContext(ctxt);
14993 return(res);
14994}
14995
14996/**
14997 * xmlXPathEvalExpression:
14998 * @str: the XPath expression
14999 * @ctxt: the XPath context
15000 *
15001 * Evaluate the XPath expression in the given context.
15002 *
15003 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15004 * the caller has to free the object.
15005 */
15006xmlXPathObjectPtr
15007xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
15008 xmlXPathParserContextPtr pctxt;
15009 xmlXPathObjectPtr res, tmp;
15010 int stack = 0;
15011
William M. Brackf13f77f2004-11-12 16:03:48 +000015012 CHECK_CTXT(ctxt)
Owen Taylor3473f882001-02-23 17:55:21 +000015013
William M. Brackf13f77f2004-11-12 16:03:48 +000015014 xmlXPathInit();
Owen Taylor3473f882001-02-23 17:55:21 +000015015
15016 pctxt = xmlXPathNewParserContext(str, ctxt);
William M. Brack11be2d02007-01-24 19:17:19 +000015017 if (pctxt == NULL)
15018 return NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000015019 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000015020
Daniel Veillardc465ffc2006-10-17 19:39:33 +000015021 if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
Owen Taylor3473f882001-02-23 17:55:21 +000015022 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
15023 res = NULL;
15024 } else {
15025 res = valuePop(pctxt);
15026 }
15027 do {
15028 tmp = valuePop(pctxt);
15029 if (tmp != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015030 xmlXPathReleaseObject(ctxt, tmp);
Owen Taylor3473f882001-02-23 17:55:21 +000015031 stack++;
15032 }
15033 } while (tmp != NULL);
15034 if ((stack != 0) && (res != NULL)) {
15035 xmlGenericError(xmlGenericErrorContext,
15036 "xmlXPathEvalExpression: %d object left on the stack\n",
15037 stack);
15038 }
15039 xmlXPathFreeParserContext(pctxt);
15040 return(res);
15041}
15042
Daniel Veillard42766c02002-08-22 20:52:17 +000015043/************************************************************************
15044 * *
15045 * Extra functions not pertaining to the XPath spec *
15046 * *
15047 ************************************************************************/
15048/**
15049 * xmlXPathEscapeUriFunction:
15050 * @ctxt: the XPath Parser context
15051 * @nargs: the number of arguments
15052 *
15053 * Implement the escape-uri() XPath function
15054 * string escape-uri(string $str, bool $escape-reserved)
15055 *
15056 * This function applies the URI escaping rules defined in section 2 of [RFC
15057 * 2396] to the string supplied as $uri-part, which typically represents all
15058 * or part of a URI. The effect of the function is to replace any special
15059 * character in the string by an escape sequence of the form %xx%yy...,
15060 * where xxyy... is the hexadecimal representation of the octets used to
15061 * represent the character in UTF-8.
15062 *
15063 * The set of characters that are escaped depends on the setting of the
15064 * boolean argument $escape-reserved.
15065 *
15066 * If $escape-reserved is true, all characters are escaped other than lower
15067 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15068 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15069 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15070 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15071 * A-F).
15072 *
15073 * If $escape-reserved is false, the behavior differs in that characters
15074 * referred to in [RFC 2396] as reserved characters are not escaped. These
15075 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
Daniel Veillard45490ae2008-07-29 09:13:19 +000015076 *
Daniel Veillard42766c02002-08-22 20:52:17 +000015077 * [RFC 2396] does not define whether escaped URIs should use lower case or
15078 * upper case for hexadecimal digits. To ensure that escaped URIs can be
15079 * compared using string comparison functions, this function must always use
15080 * the upper-case letters A-F.
Daniel Veillard45490ae2008-07-29 09:13:19 +000015081 *
Daniel Veillard42766c02002-08-22 20:52:17 +000015082 * Generally, $escape-reserved should be set to true when escaping a string
15083 * that is to form a single part of a URI, and to false when escaping an
15084 * entire URI or URI reference.
Daniel Veillard45490ae2008-07-29 09:13:19 +000015085 *
15086 * In the case of non-ascii characters, the string is encoded according to
Daniel Veillard42766c02002-08-22 20:52:17 +000015087 * utf-8 and then converted according to RFC 2396.
15088 *
15089 * Examples
Daniel Veillard45490ae2008-07-29 09:13:19 +000015090 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
Daniel Veillard42766c02002-08-22 20:52:17 +000015091 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15092 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15093 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15094 *
15095 */
Daniel Veillard118aed72002-09-24 14:13:13 +000015096static void
Daniel Veillard42766c02002-08-22 20:52:17 +000015097xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15098 xmlXPathObjectPtr str;
15099 int escape_reserved;
15100 xmlBufferPtr target;
15101 xmlChar *cptr;
15102 xmlChar escape[4];
Daniel Veillard45490ae2008-07-29 09:13:19 +000015103
Daniel Veillard42766c02002-08-22 20:52:17 +000015104 CHECK_ARITY(2);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015105
Daniel Veillard42766c02002-08-22 20:52:17 +000015106 escape_reserved = xmlXPathPopBoolean(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015107
Daniel Veillard42766c02002-08-22 20:52:17 +000015108 CAST_TO_STRING;
15109 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015110
Daniel Veillard42766c02002-08-22 20:52:17 +000015111 target = xmlBufferCreate();
Daniel Veillard45490ae2008-07-29 09:13:19 +000015112
Daniel Veillard42766c02002-08-22 20:52:17 +000015113 escape[0] = '%';
15114 escape[3] = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000015115
Daniel Veillard42766c02002-08-22 20:52:17 +000015116 if (target) {
15117 for (cptr = str->stringval; *cptr; cptr++) {
15118 if ((*cptr >= 'A' && *cptr <= 'Z') ||
15119 (*cptr >= 'a' && *cptr <= 'z') ||
15120 (*cptr >= '0' && *cptr <= '9') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000015121 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
Daniel Veillard42766c02002-08-22 20:52:17 +000015122 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
15123 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000015124 (*cptr == '%' &&
Daniel Veillard42766c02002-08-22 20:52:17 +000015125 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15126 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15127 (cptr[1] >= '0' && cptr[1] <= '9')) &&
15128 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15129 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15130 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15131 (!escape_reserved &&
15132 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15133 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15134 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15135 *cptr == ','))) {
15136 xmlBufferAdd(target, cptr, 1);
15137 } else {
15138 if ((*cptr >> 4) < 10)
15139 escape[1] = '0' + (*cptr >> 4);
15140 else
15141 escape[1] = 'A' - 10 + (*cptr >> 4);
15142 if ((*cptr & 0xF) < 10)
15143 escape[2] = '0' + (*cptr & 0xF);
15144 else
15145 escape[2] = 'A' - 10 + (*cptr & 0xF);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015146
Daniel Veillard42766c02002-08-22 20:52:17 +000015147 xmlBufferAdd(target, &escape[0], 3);
15148 }
15149 }
15150 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015151 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15152 xmlBufferContent(target)));
Daniel Veillard42766c02002-08-22 20:52:17 +000015153 xmlBufferFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015154 xmlXPathReleaseObject(ctxt->context, str);
Daniel Veillard42766c02002-08-22 20:52:17 +000015155}
15156
Owen Taylor3473f882001-02-23 17:55:21 +000015157/**
15158 * xmlXPathRegisterAllFunctions:
15159 * @ctxt: the XPath context
15160 *
15161 * Registers all default XPath functions in this context
15162 */
15163void
15164xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15165{
15166 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15167 xmlXPathBooleanFunction);
15168 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15169 xmlXPathCeilingFunction);
15170 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15171 xmlXPathCountFunction);
15172 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15173 xmlXPathConcatFunction);
15174 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15175 xmlXPathContainsFunction);
15176 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15177 xmlXPathIdFunction);
15178 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15179 xmlXPathFalseFunction);
15180 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15181 xmlXPathFloorFunction);
15182 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15183 xmlXPathLastFunction);
15184 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15185 xmlXPathLangFunction);
15186 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15187 xmlXPathLocalNameFunction);
15188 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15189 xmlXPathNotFunction);
15190 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15191 xmlXPathNameFunction);
15192 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15193 xmlXPathNamespaceURIFunction);
15194 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15195 xmlXPathNormalizeFunction);
15196 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15197 xmlXPathNumberFunction);
15198 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15199 xmlXPathPositionFunction);
15200 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15201 xmlXPathRoundFunction);
15202 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15203 xmlXPathStringFunction);
15204 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15205 xmlXPathStringLengthFunction);
15206 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15207 xmlXPathStartsWithFunction);
15208 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15209 xmlXPathSubstringFunction);
15210 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15211 xmlXPathSubstringBeforeFunction);
15212 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15213 xmlXPathSubstringAfterFunction);
15214 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15215 xmlXPathSumFunction);
15216 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15217 xmlXPathTrueFunction);
15218 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15219 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000015220
15221 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15222 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15223 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000015224}
15225
15226#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000015227#define bottom_xpath
15228#include "elfgcchack.h"