blob: b59ac5af46ef9a2ddd32d5a3a0d95b5ab034a86c [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",
255 "?? Unknown error ??\n" /* Must be last in the list! */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000256};
William M. Brackcd65bc92005-01-06 09:39:18 +0000257#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
258 sizeof(xmlXPathErrorMessages[0])) - 1)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000259/**
260 * xmlXPathErrMemory:
261 * @ctxt: an XPath context
262 * @extra: extra informations
263 *
264 * Handle a redefinition of attribute error
265 */
266static void
267xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
268{
269 if (ctxt != NULL) {
270 if (extra) {
271 xmlChar buf[200];
272
273 xmlStrPrintf(buf, 200,
274 BAD_CAST "Memory allocation failed : %s\n",
275 extra);
276 ctxt->lastError.message = (char *) xmlStrdup(buf);
277 } else {
278 ctxt->lastError.message = (char *)
279 xmlStrdup(BAD_CAST "Memory allocation failed\n");
280 }
281 ctxt->lastError.domain = XML_FROM_XPATH;
282 ctxt->lastError.code = XML_ERR_NO_MEMORY;
283 if (ctxt->error != NULL)
284 ctxt->error(ctxt->userData, &ctxt->lastError);
285 } else {
286 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000287 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000288 NULL, NULL, XML_FROM_XPATH,
289 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
290 extra, NULL, NULL, 0, 0,
291 "Memory allocation failed : %s\n", extra);
292 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000293 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000294 NULL, NULL, XML_FROM_XPATH,
295 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
296 NULL, NULL, NULL, 0, 0,
297 "Memory allocation failed\n");
298 }
299}
300
301/**
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000302 * xmlXPathPErrMemory:
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000303 * @ctxt: an XPath parser context
304 * @extra: extra informations
305 *
306 * Handle a redefinition of attribute error
307 */
308static void
309xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
310{
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000311 if (ctxt == NULL)
312 xmlXPathErrMemory(NULL, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000313 else {
314 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000315 xmlXPathErrMemory(ctxt->context, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000316 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000317}
318
319/**
320 * xmlXPathErr:
321 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000322 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000323 *
William M. Brackcd65bc92005-01-06 09:39:18 +0000324 * Handle an XPath error
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000325 */
326void
327xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
328{
William M. Brackcd65bc92005-01-06 09:39:18 +0000329 if ((error < 0) || (error > MAXERRNO))
330 error = MAXERRNO;
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000331 if (ctxt == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000332 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000333 NULL, NULL, XML_FROM_XPATH,
334 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
335 XML_ERR_ERROR, NULL, 0,
336 NULL, NULL, NULL, 0, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200337 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000338 return;
339 }
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000340 ctxt->error = error;
341 if (ctxt->context == NULL) {
342 __xmlRaiseError(NULL, NULL, NULL,
343 NULL, NULL, XML_FROM_XPATH,
344 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
345 XML_ERR_ERROR, NULL, 0,
346 (const char *) ctxt->base, NULL, NULL,
347 ctxt->cur - ctxt->base, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200348 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000349 return;
350 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +0000351
352 /* cleanup current last error */
Daniel Veillard45490ae2008-07-29 09:13:19 +0000353 xmlResetError(&ctxt->context->lastError);
Aleksey Sanin1b2be102006-05-31 20:53:43 +0000354
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000355 ctxt->context->lastError.domain = XML_FROM_XPATH;
356 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
357 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000358 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000359 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
360 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
361 ctxt->context->lastError.node = ctxt->context->debugNode;
362 if (ctxt->context->error != NULL) {
363 ctxt->context->error(ctxt->context->userData,
364 &ctxt->context->lastError);
365 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000366 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000367 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
368 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
369 XML_ERR_ERROR, NULL, 0,
370 (const char *) ctxt->base, NULL, NULL,
371 ctxt->cur - ctxt->base, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200372 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000373 }
374
375}
376
377/**
378 * xmlXPatherror:
379 * @ctxt: the XPath Parser context
380 * @file: the file name
381 * @line: the line number
382 * @no: the error number
383 *
384 * Formats an error message.
385 */
386void
387xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
388 int line ATTRIBUTE_UNUSED, int no) {
389 xmlXPathErr(ctxt, no);
390}
391
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000392/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000393 * *
394 * Utilities *
395 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000396 ************************************************************************/
397
398/**
399 * xsltPointerList:
400 *
401 * Pointer-list for various purposes.
402 */
403typedef struct _xmlPointerList xmlPointerList;
404typedef xmlPointerList *xmlPointerListPtr;
405struct _xmlPointerList {
406 void **items;
407 int number;
408 int size;
409};
410/*
411* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
412* and here, we should make the functions public.
413*/
414static int
Daniel Veillard45490ae2008-07-29 09:13:19 +0000415xmlPointerListAddSize(xmlPointerListPtr list,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000416 void *item,
417 int initialSize)
418{
419 if (list->items == NULL) {
420 if (initialSize <= 0)
421 initialSize = 1;
422 list->items = (void **) xmlMalloc(
423 initialSize * sizeof(void *));
424 if (list->items == NULL) {
425 xmlXPathErrMemory(NULL,
426 "xmlPointerListCreate: allocating item\n");
427 return(-1);
428 }
429 list->number = 0;
430 list->size = initialSize;
431 } else if (list->size <= list->number) {
432 list->size *= 2;
433 list->items = (void **) xmlRealloc(list->items,
434 list->size * sizeof(void *));
435 if (list->items == NULL) {
436 xmlXPathErrMemory(NULL,
437 "xmlPointerListCreate: re-allocating item\n");
438 list->size = 0;
439 return(-1);
440 }
441 }
442 list->items[list->number++] = item;
443 return(0);
444}
445
446/**
447 * xsltPointerListCreate:
448 *
449 * Creates an xsltPointerList structure.
450 *
451 * Returns a xsltPointerList structure or NULL in case of an error.
452 */
453static xmlPointerListPtr
454xmlPointerListCreate(int initialSize)
455{
456 xmlPointerListPtr ret;
457
458 ret = xmlMalloc(sizeof(xmlPointerList));
459 if (ret == NULL) {
460 xmlXPathErrMemory(NULL,
461 "xmlPointerListCreate: allocating item\n");
462 return (NULL);
463 }
464 memset(ret, 0, sizeof(xmlPointerList));
465 if (initialSize > 0) {
466 xmlPointerListAddSize(ret, NULL, initialSize);
467 ret->number = 0;
468 }
469 return (ret);
470}
471
472/**
473 * xsltPointerListFree:
474 *
475 * Frees the xsltPointerList structure. This does not free
476 * the content of the list.
477 */
478static void
479xmlPointerListFree(xmlPointerListPtr list)
480{
481 if (list == NULL)
482 return;
483 if (list->items != NULL)
484 xmlFree(list->items);
485 xmlFree(list);
486}
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000487
488/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000489 * *
490 * Parser Types *
491 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000492 ************************************************************************/
493
494/*
495 * Types are private:
496 */
497
498typedef enum {
499 XPATH_OP_END=0,
500 XPATH_OP_AND,
501 XPATH_OP_OR,
502 XPATH_OP_EQUAL,
503 XPATH_OP_CMP,
504 XPATH_OP_PLUS,
505 XPATH_OP_MULT,
506 XPATH_OP_UNION,
507 XPATH_OP_ROOT,
508 XPATH_OP_NODE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000509 XPATH_OP_RESET, /* 10 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000510 XPATH_OP_COLLECT,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000511 XPATH_OP_VALUE, /* 12 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000512 XPATH_OP_VARIABLE,
513 XPATH_OP_FUNCTION,
514 XPATH_OP_ARG,
515 XPATH_OP_PREDICATE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000516 XPATH_OP_FILTER, /* 17 */
517 XPATH_OP_SORT /* 18 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000518#ifdef LIBXML_XPTR_ENABLED
519 ,XPATH_OP_RANGETO
520#endif
521} xmlXPathOp;
522
523typedef enum {
524 AXIS_ANCESTOR = 1,
525 AXIS_ANCESTOR_OR_SELF,
526 AXIS_ATTRIBUTE,
527 AXIS_CHILD,
528 AXIS_DESCENDANT,
529 AXIS_DESCENDANT_OR_SELF,
530 AXIS_FOLLOWING,
531 AXIS_FOLLOWING_SIBLING,
532 AXIS_NAMESPACE,
533 AXIS_PARENT,
534 AXIS_PRECEDING,
535 AXIS_PRECEDING_SIBLING,
Daniel Veillard45490ae2008-07-29 09:13:19 +0000536 AXIS_SELF
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000537} xmlXPathAxisVal;
538
539typedef enum {
540 NODE_TEST_NONE = 0,
541 NODE_TEST_TYPE = 1,
542 NODE_TEST_PI = 2,
543 NODE_TEST_ALL = 3,
544 NODE_TEST_NS = 4,
545 NODE_TEST_NAME = 5
546} xmlXPathTestVal;
547
548typedef enum {
549 NODE_TYPE_NODE = 0,
550 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
551 NODE_TYPE_TEXT = XML_TEXT_NODE,
Daniel Veillard45490ae2008-07-29 09:13:19 +0000552 NODE_TYPE_PI = XML_PI_NODE
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000553} xmlXPathTypeVal;
554
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +0000555#define XP_REWRITE_DOS_CHILD_ELEM 1
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000556
557typedef struct _xmlXPathStepOp xmlXPathStepOp;
558typedef xmlXPathStepOp *xmlXPathStepOpPtr;
559struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000560 xmlXPathOp op; /* The identifier of the operation */
561 int ch1; /* First child */
562 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000563 int value;
564 int value2;
565 int value3;
566 void *value4;
567 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000568 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000569 void *cacheURI;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +0000570 int rewriteType;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000571};
572
573struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000574 int nbStep; /* Number of steps in this expression */
575 int maxStep; /* Maximum number of steps allocated */
576 xmlXPathStepOp *steps; /* ops for computation of this expression */
577 int last; /* index of last step in expression */
578 xmlChar *expr; /* the expression being computed */
Daniel Veillard4773df22004-01-23 13:15:13 +0000579 xmlDictPtr dict; /* the dictionnary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000580#ifdef DEBUG_EVAL_COUNTS
581 int nb;
582 xmlChar *string;
583#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000584#ifdef XPATH_STREAMING
585 xmlPatternPtr stream;
586#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000587};
588
589/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000590 * *
591 * Forward declarations *
592 * *
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000593 ************************************************************************/
594static void
595xmlXPathFreeValueTree(xmlNodeSetPtr obj);
596static void
597xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
598static int
599xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
600 xmlXPathStepOpPtr op, xmlNodePtr *first);
601static int
602xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +0000603 xmlXPathStepOpPtr op,
604 int isPredicate);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000605
606/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000607 * *
608 * Parser Type functions *
609 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000610 ************************************************************************/
611
612/**
613 * xmlXPathNewCompExpr:
614 *
615 * Create a new Xpath component
616 *
617 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
618 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000619static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000620xmlXPathNewCompExpr(void) {
621 xmlXPathCompExprPtr cur;
622
623 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
624 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000625 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000626 return(NULL);
627 }
628 memset(cur, 0, sizeof(xmlXPathCompExpr));
629 cur->maxStep = 10;
630 cur->nbStep = 0;
631 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
632 sizeof(xmlXPathStepOp));
633 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000634 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000635 xmlFree(cur);
636 return(NULL);
637 }
638 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
639 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000640#ifdef DEBUG_EVAL_COUNTS
641 cur->nb = 0;
642#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000643 return(cur);
644}
645
646/**
647 * xmlXPathFreeCompExpr:
648 * @comp: an XPATH comp
649 *
650 * Free up the memory allocated by @comp
651 */
652void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000653xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
654{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000655 xmlXPathStepOpPtr op;
656 int i;
657
658 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000659 return;
Daniel Veillard4773df22004-01-23 13:15:13 +0000660 if (comp->dict == NULL) {
661 for (i = 0; i < comp->nbStep; i++) {
662 op = &comp->steps[i];
663 if (op->value4 != NULL) {
664 if (op->op == XPATH_OP_VALUE)
665 xmlXPathFreeObject(op->value4);
666 else
667 xmlFree(op->value4);
668 }
669 if (op->value5 != NULL)
670 xmlFree(op->value5);
671 }
672 } else {
673 for (i = 0; i < comp->nbStep; i++) {
674 op = &comp->steps[i];
675 if (op->value4 != NULL) {
676 if (op->op == XPATH_OP_VALUE)
677 xmlXPathFreeObject(op->value4);
678 }
679 }
680 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000681 }
682 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000683 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000684 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000685#ifdef DEBUG_EVAL_COUNTS
686 if (comp->string != NULL) {
687 xmlFree(comp->string);
688 }
689#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000690#ifdef XPATH_STREAMING
691 if (comp->stream != NULL) {
692 xmlFreePatternList(comp->stream);
693 }
694#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000695 if (comp->expr != NULL) {
696 xmlFree(comp->expr);
697 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000698
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000699 xmlFree(comp);
700}
701
702/**
703 * xmlXPathCompExprAdd:
704 * @comp: the compiled expression
705 * @ch1: first child index
706 * @ch2: second child index
707 * @op: an op
708 * @value: the first int value
709 * @value2: the second int value
710 * @value3: the third int value
711 * @value4: the first string value
712 * @value5: the second string value
713 *
William M. Brack08171912003-12-29 02:52:11 +0000714 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000715 *
716 * Returns -1 in case of failure, the index otherwise
717 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000718static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000719xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
720 xmlXPathOp op, int value,
721 int value2, int value3, void *value4, void *value5) {
722 if (comp->nbStep >= comp->maxStep) {
723 xmlXPathStepOp *real;
724
725 comp->maxStep *= 2;
726 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
727 comp->maxStep * sizeof(xmlXPathStepOp));
728 if (real == NULL) {
729 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000730 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000731 return(-1);
732 }
733 comp->steps = real;
734 }
735 comp->last = comp->nbStep;
Kasimier T. Buchcik6422d912006-06-26 14:31:53 +0000736 comp->steps[comp->nbStep].rewriteType = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000737 comp->steps[comp->nbStep].ch1 = ch1;
738 comp->steps[comp->nbStep].ch2 = ch2;
739 comp->steps[comp->nbStep].op = op;
740 comp->steps[comp->nbStep].value = value;
741 comp->steps[comp->nbStep].value2 = value2;
742 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +0000743 if ((comp->dict != NULL) &&
744 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
745 (op == XPATH_OP_COLLECT))) {
746 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000747 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000748 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000749 xmlFree(value4);
750 } else
751 comp->steps[comp->nbStep].value4 = NULL;
752 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000753 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000754 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000755 xmlFree(value5);
756 } else
757 comp->steps[comp->nbStep].value5 = NULL;
758 } else {
759 comp->steps[comp->nbStep].value4 = value4;
760 comp->steps[comp->nbStep].value5 = value5;
761 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000762 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000763 return(comp->nbStep++);
764}
765
Daniel Veillardf06307e2001-07-03 10:35:50 +0000766/**
767 * xmlXPathCompSwap:
768 * @comp: the compiled expression
769 * @op: operation index
770 *
771 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000772 */
773static void
774xmlXPathCompSwap(xmlXPathStepOpPtr op) {
775 int tmp;
776
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000777#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000778 /*
779 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +0000780 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +0000781 * application
782 */
783 if (xmlXPathDisableOptimizer)
784 return;
785#endif
786
Daniel Veillardf06307e2001-07-03 10:35:50 +0000787 tmp = op->ch1;
788 op->ch1 = op->ch2;
789 op->ch2 = tmp;
790}
791
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000792#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
793 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
794 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000795#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
796 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
797 (op), (val), (val2), (val3), (val4), (val5))
798
Daniel Veillard45490ae2008-07-29 09:13:19 +0000799#define PUSH_LEAVE_EXPR(op, val, val2) \
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000800xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
801
Daniel Veillard45490ae2008-07-29 09:13:19 +0000802#define PUSH_UNARY_EXPR(op, ch, val, val2) \
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000803xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
804
Daniel Veillard45490ae2008-07-29 09:13:19 +0000805#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +0000806xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
807 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000808
809/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000810 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +0000811 * XPath object cache structures *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000812 * *
813 ************************************************************************/
814
815/* #define XP_DEFAULT_CACHE_ON */
816
Kasimier T. Buchcik58694692006-05-31 12:37:28 +0000817#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000818
Kasimier T. Buchcik58694692006-05-31 12:37:28 +0000819typedef struct _xmlXPathContextCache xmlXPathContextCache;
820typedef xmlXPathContextCache *xmlXPathContextCachePtr;
821struct _xmlXPathContextCache {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +0000822 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
823 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
824 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
825 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
826 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000827 int maxNodeset;
828 int maxString;
829 int maxBoolean;
830 int maxNumber;
831 int maxMisc;
832#ifdef XP_DEBUG_OBJ_USAGE
833 int dbgCachedAll;
834 int dbgCachedNodeset;
835 int dbgCachedString;
836 int dbgCachedBool;
837 int dbgCachedNumber;
838 int dbgCachedPoint;
839 int dbgCachedRange;
840 int dbgCachedLocset;
841 int dbgCachedUsers;
842 int dbgCachedXSLTTree;
Daniel Veillard45490ae2008-07-29 09:13:19 +0000843 int dbgCachedUndefined;
844
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000845
846 int dbgReusedAll;
847 int dbgReusedNodeset;
848 int dbgReusedString;
849 int dbgReusedBool;
850 int dbgReusedNumber;
851 int dbgReusedPoint;
852 int dbgReusedRange;
853 int dbgReusedLocset;
854 int dbgReusedUsers;
855 int dbgReusedXSLTTree;
856 int dbgReusedUndefined;
857
858#endif
859};
860
861/************************************************************************
862 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +0000863 * Debugging related functions *
Owen Taylor3473f882001-02-23 17:55:21 +0000864 * *
865 ************************************************************************/
866
Daniel Veillard45490ae2008-07-29 09:13:19 +0000867#define STRANGE \
Owen Taylor3473f882001-02-23 17:55:21 +0000868 xmlGenericError(xmlGenericErrorContext, \
869 "Internal error at %s:%d\n", \
870 __FILE__, __LINE__);
871
872#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000873static void
874xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000875 int i;
876 char shift[100];
877
878 for (i = 0;((i < depth) && (i < 25));i++)
879 shift[2 * i] = shift[2 * i + 1] = ' ';
880 shift[2 * i] = shift[2 * i + 1] = 0;
881 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200882 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +0000883 fprintf(output, "Node is NULL !\n");
884 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +0000885
Owen Taylor3473f882001-02-23 17:55:21 +0000886 }
887
888 if ((cur->type == XML_DOCUMENT_NODE) ||
889 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200890 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +0000891 fprintf(output, " /\n");
892 } else if (cur->type == XML_ATTRIBUTE_NODE)
893 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
894 else
895 xmlDebugDumpOneNode(output, cur, depth);
896}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000897static void
898xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000899 xmlNodePtr tmp;
900 int i;
901 char shift[100];
902
903 for (i = 0;((i < depth) && (i < 25));i++)
904 shift[2 * i] = shift[2 * i + 1] = ' ';
905 shift[2 * i] = shift[2 * i + 1] = 0;
906 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200907 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000908 fprintf(output, "Node is NULL !\n");
909 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +0000910
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000911 }
912
913 while (cur != NULL) {
914 tmp = cur;
915 cur = cur->next;
916 xmlDebugDumpOneNode(output, tmp, depth);
917 }
918}
Owen Taylor3473f882001-02-23 17:55:21 +0000919
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000920static void
921xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000922 int i;
923 char shift[100];
924
925 for (i = 0;((i < depth) && (i < 25));i++)
926 shift[2 * i] = shift[2 * i + 1] = ' ';
927 shift[2 * i] = shift[2 * i + 1] = 0;
928
929 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200930 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +0000931 fprintf(output, "NodeSet is NULL !\n");
932 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +0000933
Owen Taylor3473f882001-02-23 17:55:21 +0000934 }
935
Daniel Veillard911f49a2001-04-07 15:39:35 +0000936 if (cur != NULL) {
937 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
938 for (i = 0;i < cur->nodeNr;i++) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200939 fprintf(output, "%s", shift);
Daniel Veillard911f49a2001-04-07 15:39:35 +0000940 fprintf(output, "%d", i + 1);
941 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
942 }
Owen Taylor3473f882001-02-23 17:55:21 +0000943 }
944}
945
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000946static void
947xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000948 int i;
949 char shift[100];
950
951 for (i = 0;((i < depth) && (i < 25));i++)
952 shift[2 * i] = shift[2 * i + 1] = ' ';
953 shift[2 * i] = shift[2 * i + 1] = 0;
954
955 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200956 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000957 fprintf(output, "Value Tree is NULL !\n");
958 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +0000959
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000960 }
961
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200962 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000963 fprintf(output, "%d", i + 1);
964 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
965}
Owen Taylor3473f882001-02-23 17:55:21 +0000966#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000967static void
968xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000969 int i;
970 char shift[100];
971
972 for (i = 0;((i < depth) && (i < 25));i++)
973 shift[2 * i] = shift[2 * i + 1] = ' ';
974 shift[2 * i] = shift[2 * i + 1] = 0;
975
976 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200977 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +0000978 fprintf(output, "LocationSet is NULL !\n");
979 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +0000980
Owen Taylor3473f882001-02-23 17:55:21 +0000981 }
982
983 for (i = 0;i < cur->locNr;i++) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200984 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +0000985 fprintf(output, "%d : ", i + 1);
986 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
987 }
988}
Daniel Veillard017b1082001-06-21 11:20:21 +0000989#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000990
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000991/**
992 * xmlXPathDebugDumpObject:
993 * @output: the FILE * to dump the output
994 * @cur: the object to inspect
995 * @depth: indentation level
996 *
997 * Dump the content of the object for debugging purposes
998 */
999void
1000xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001001 int i;
1002 char shift[100];
1003
Daniel Veillarda82b1822004-11-08 16:24:57 +00001004 if (output == NULL) return;
1005
Owen Taylor3473f882001-02-23 17:55:21 +00001006 for (i = 0;((i < depth) && (i < 25));i++)
1007 shift[2 * i] = shift[2 * i + 1] = ' ';
1008 shift[2 * i] = shift[2 * i + 1] = 0;
1009
Kasimier T. Buchcik97258712006-01-05 12:30:43 +00001010
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001011 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001012
1013 if (cur == NULL) {
1014 fprintf(output, "Object is empty (NULL)\n");
1015 return;
1016 }
1017 switch(cur->type) {
1018 case XPATH_UNDEFINED:
1019 fprintf(output, "Object is uninitialized\n");
1020 break;
1021 case XPATH_NODESET:
1022 fprintf(output, "Object is a Node Set :\n");
1023 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1024 break;
1025 case XPATH_XSLT_TREE:
1026 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001027 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +00001028 break;
1029 case XPATH_BOOLEAN:
1030 fprintf(output, "Object is a Boolean : ");
1031 if (cur->boolval) fprintf(output, "true\n");
1032 else fprintf(output, "false\n");
1033 break;
1034 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +00001035 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001036 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001037 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001038 break;
1039 case -1:
1040 fprintf(output, "Object is a number : -Infinity\n");
1041 break;
1042 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001043 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001044 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001045 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1046 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001047 } else {
1048 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1049 }
1050 }
Owen Taylor3473f882001-02-23 17:55:21 +00001051 break;
1052 case XPATH_STRING:
1053 fprintf(output, "Object is a string : ");
1054 xmlDebugDumpString(output, cur->stringval);
1055 fprintf(output, "\n");
1056 break;
1057 case XPATH_POINT:
1058 fprintf(output, "Object is a point : index %d in node", cur->index);
1059 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1060 fprintf(output, "\n");
1061 break;
1062 case XPATH_RANGE:
1063 if ((cur->user2 == NULL) ||
1064 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1065 fprintf(output, "Object is a collapsed range :\n");
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001066 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001067 if (cur->index >= 0)
1068 fprintf(output, "index %d in ", cur->index);
1069 fprintf(output, "node\n");
1070 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1071 depth + 1);
1072 } else {
1073 fprintf(output, "Object is a range :\n");
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001074 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001075 fprintf(output, "From ");
1076 if (cur->index >= 0)
1077 fprintf(output, "index %d in ", cur->index);
1078 fprintf(output, "node\n");
1079 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1080 depth + 1);
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001081 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001082 fprintf(output, "To ");
1083 if (cur->index2 >= 0)
1084 fprintf(output, "index %d in ", cur->index2);
1085 fprintf(output, "node\n");
1086 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1087 depth + 1);
1088 fprintf(output, "\n");
1089 }
1090 break;
1091 case XPATH_LOCATIONSET:
1092#if defined(LIBXML_XPTR_ENABLED)
1093 fprintf(output, "Object is a Location Set:\n");
1094 xmlXPathDebugDumpLocationSet(output,
1095 (xmlLocationSetPtr) cur->user, depth);
1096#endif
1097 break;
1098 case XPATH_USERS:
1099 fprintf(output, "Object is user defined\n");
1100 break;
1101 }
1102}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001103
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001104static void
1105xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001106 xmlXPathStepOpPtr op, int depth) {
1107 int i;
1108 char shift[100];
1109
1110 for (i = 0;((i < depth) && (i < 25));i++)
1111 shift[2 * i] = shift[2 * i + 1] = ' ';
1112 shift[2 * i] = shift[2 * i + 1] = 0;
1113
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001114 fprintf(output, "%s", shift);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001115 if (op == NULL) {
1116 fprintf(output, "Step is NULL\n");
1117 return;
1118 }
1119 switch (op->op) {
1120 case XPATH_OP_END:
1121 fprintf(output, "END"); break;
1122 case XPATH_OP_AND:
1123 fprintf(output, "AND"); break;
1124 case XPATH_OP_OR:
1125 fprintf(output, "OR"); break;
1126 case XPATH_OP_EQUAL:
1127 if (op->value)
1128 fprintf(output, "EQUAL =");
1129 else
1130 fprintf(output, "EQUAL !=");
1131 break;
1132 case XPATH_OP_CMP:
1133 if (op->value)
1134 fprintf(output, "CMP <");
1135 else
1136 fprintf(output, "CMP >");
1137 if (!op->value2)
1138 fprintf(output, "=");
1139 break;
1140 case XPATH_OP_PLUS:
1141 if (op->value == 0)
1142 fprintf(output, "PLUS -");
1143 else if (op->value == 1)
1144 fprintf(output, "PLUS +");
1145 else if (op->value == 2)
1146 fprintf(output, "PLUS unary -");
1147 else if (op->value == 3)
1148 fprintf(output, "PLUS unary - -");
1149 break;
1150 case XPATH_OP_MULT:
1151 if (op->value == 0)
1152 fprintf(output, "MULT *");
1153 else if (op->value == 1)
1154 fprintf(output, "MULT div");
1155 else
1156 fprintf(output, "MULT mod");
1157 break;
1158 case XPATH_OP_UNION:
1159 fprintf(output, "UNION"); break;
1160 case XPATH_OP_ROOT:
1161 fprintf(output, "ROOT"); break;
1162 case XPATH_OP_NODE:
1163 fprintf(output, "NODE"); break;
1164 case XPATH_OP_RESET:
1165 fprintf(output, "RESET"); break;
1166 case XPATH_OP_SORT:
1167 fprintf(output, "SORT"); break;
1168 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +00001169 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1170 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1171 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001172 const xmlChar *prefix = op->value4;
1173 const xmlChar *name = op->value5;
1174
1175 fprintf(output, "COLLECT ");
1176 switch (axis) {
1177 case AXIS_ANCESTOR:
1178 fprintf(output, " 'ancestors' "); break;
1179 case AXIS_ANCESTOR_OR_SELF:
1180 fprintf(output, " 'ancestors-or-self' "); break;
1181 case AXIS_ATTRIBUTE:
1182 fprintf(output, " 'attributes' "); break;
1183 case AXIS_CHILD:
1184 fprintf(output, " 'child' "); break;
1185 case AXIS_DESCENDANT:
1186 fprintf(output, " 'descendant' "); break;
1187 case AXIS_DESCENDANT_OR_SELF:
1188 fprintf(output, " 'descendant-or-self' "); break;
1189 case AXIS_FOLLOWING:
1190 fprintf(output, " 'following' "); break;
1191 case AXIS_FOLLOWING_SIBLING:
1192 fprintf(output, " 'following-siblings' "); break;
1193 case AXIS_NAMESPACE:
1194 fprintf(output, " 'namespace' "); break;
1195 case AXIS_PARENT:
1196 fprintf(output, " 'parent' "); break;
1197 case AXIS_PRECEDING:
1198 fprintf(output, " 'preceding' "); break;
1199 case AXIS_PRECEDING_SIBLING:
1200 fprintf(output, " 'preceding-sibling' "); break;
1201 case AXIS_SELF:
1202 fprintf(output, " 'self' "); break;
1203 }
1204 switch (test) {
1205 case NODE_TEST_NONE:
1206 fprintf(output, "'none' "); break;
1207 case NODE_TEST_TYPE:
1208 fprintf(output, "'type' "); break;
1209 case NODE_TEST_PI:
1210 fprintf(output, "'PI' "); break;
1211 case NODE_TEST_ALL:
1212 fprintf(output, "'all' "); break;
1213 case NODE_TEST_NS:
1214 fprintf(output, "'namespace' "); break;
1215 case NODE_TEST_NAME:
1216 fprintf(output, "'name' "); break;
1217 }
1218 switch (type) {
1219 case NODE_TYPE_NODE:
1220 fprintf(output, "'node' "); break;
1221 case NODE_TYPE_COMMENT:
1222 fprintf(output, "'comment' "); break;
1223 case NODE_TYPE_TEXT:
1224 fprintf(output, "'text' "); break;
1225 case NODE_TYPE_PI:
1226 fprintf(output, "'PI' "); break;
1227 }
1228 if (prefix != NULL)
1229 fprintf(output, "%s:", prefix);
1230 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001231 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001232 break;
1233
1234 }
1235 case XPATH_OP_VALUE: {
1236 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1237
1238 fprintf(output, "ELEM ");
1239 xmlXPathDebugDumpObject(output, object, 0);
1240 goto finish;
1241 }
1242 case XPATH_OP_VARIABLE: {
1243 const xmlChar *prefix = op->value5;
1244 const xmlChar *name = op->value4;
1245
1246 if (prefix != NULL)
1247 fprintf(output, "VARIABLE %s:%s", prefix, name);
1248 else
1249 fprintf(output, "VARIABLE %s", name);
1250 break;
1251 }
1252 case XPATH_OP_FUNCTION: {
1253 int nbargs = op->value;
1254 const xmlChar *prefix = op->value5;
1255 const xmlChar *name = op->value4;
1256
1257 if (prefix != NULL)
1258 fprintf(output, "FUNCTION %s:%s(%d args)",
1259 prefix, name, nbargs);
1260 else
1261 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1262 break;
1263 }
1264 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1265 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001266 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001267#ifdef LIBXML_XPTR_ENABLED
1268 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1269#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001270 default:
1271 fprintf(output, "UNKNOWN %d\n", op->op); return;
1272 }
1273 fprintf(output, "\n");
1274finish:
1275 if (op->ch1 >= 0)
1276 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1277 if (op->ch2 >= 0)
1278 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1279}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001280
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001281/**
1282 * xmlXPathDebugDumpCompExpr:
1283 * @output: the FILE * for the output
1284 * @comp: the precompiled XPath expression
1285 * @depth: the indentation level.
1286 *
1287 * Dumps the tree of the compiled XPath expression.
1288 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001289void
1290xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1291 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001292 int i;
1293 char shift[100];
1294
Daniel Veillarda82b1822004-11-08 16:24:57 +00001295 if ((output == NULL) || (comp == NULL)) return;
1296
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001297 for (i = 0;((i < depth) && (i < 25));i++)
1298 shift[2 * i] = shift[2 * i + 1] = ' ';
1299 shift[2 * i] = shift[2 * i + 1] = 0;
1300
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001301 fprintf(output, "%s", shift);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001302
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001303 fprintf(output, "Compiled Expression : %d elements\n",
1304 comp->nbStep);
1305 i = comp->last;
1306 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1307}
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001308
1309#ifdef XP_DEBUG_OBJ_USAGE
1310
1311/*
1312* XPath object usage related debugging variables.
1313*/
1314static int xmlXPathDebugObjCounterUndefined = 0;
1315static int xmlXPathDebugObjCounterNodeset = 0;
1316static int xmlXPathDebugObjCounterBool = 0;
1317static int xmlXPathDebugObjCounterNumber = 0;
1318static int xmlXPathDebugObjCounterString = 0;
1319static int xmlXPathDebugObjCounterPoint = 0;
1320static int xmlXPathDebugObjCounterRange = 0;
1321static int xmlXPathDebugObjCounterLocset = 0;
1322static int xmlXPathDebugObjCounterUsers = 0;
1323static int xmlXPathDebugObjCounterXSLTTree = 0;
1324static int xmlXPathDebugObjCounterAll = 0;
1325
1326static int xmlXPathDebugObjTotalUndefined = 0;
1327static int xmlXPathDebugObjTotalNodeset = 0;
1328static int xmlXPathDebugObjTotalBool = 0;
1329static int xmlXPathDebugObjTotalNumber = 0;
1330static int xmlXPathDebugObjTotalString = 0;
1331static int xmlXPathDebugObjTotalPoint = 0;
1332static int xmlXPathDebugObjTotalRange = 0;
1333static int xmlXPathDebugObjTotalLocset = 0;
1334static int xmlXPathDebugObjTotalUsers = 0;
1335static int xmlXPathDebugObjTotalXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001336static int xmlXPathDebugObjTotalAll = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001337
1338static int xmlXPathDebugObjMaxUndefined = 0;
1339static int xmlXPathDebugObjMaxNodeset = 0;
1340static int xmlXPathDebugObjMaxBool = 0;
1341static int xmlXPathDebugObjMaxNumber = 0;
1342static int xmlXPathDebugObjMaxString = 0;
1343static int xmlXPathDebugObjMaxPoint = 0;
1344static int xmlXPathDebugObjMaxRange = 0;
1345static int xmlXPathDebugObjMaxLocset = 0;
1346static int xmlXPathDebugObjMaxUsers = 0;
1347static int xmlXPathDebugObjMaxXSLTTree = 0;
1348static int xmlXPathDebugObjMaxAll = 0;
1349
1350/* REVISIT TODO: Make this static when committing */
1351static void
1352xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1353{
1354 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001355 if (ctxt->cache != NULL) {
1356 xmlXPathContextCachePtr cache =
1357 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001358
1359 cache->dbgCachedAll = 0;
1360 cache->dbgCachedNodeset = 0;
1361 cache->dbgCachedString = 0;
1362 cache->dbgCachedBool = 0;
1363 cache->dbgCachedNumber = 0;
1364 cache->dbgCachedPoint = 0;
1365 cache->dbgCachedRange = 0;
1366 cache->dbgCachedLocset = 0;
1367 cache->dbgCachedUsers = 0;
1368 cache->dbgCachedXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001369 cache->dbgCachedUndefined = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001370
1371 cache->dbgReusedAll = 0;
1372 cache->dbgReusedNodeset = 0;
1373 cache->dbgReusedString = 0;
1374 cache->dbgReusedBool = 0;
1375 cache->dbgReusedNumber = 0;
1376 cache->dbgReusedPoint = 0;
1377 cache->dbgReusedRange = 0;
1378 cache->dbgReusedLocset = 0;
1379 cache->dbgReusedUsers = 0;
1380 cache->dbgReusedXSLTTree = 0;
1381 cache->dbgReusedUndefined = 0;
1382 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00001383 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001384
1385 xmlXPathDebugObjCounterUndefined = 0;
1386 xmlXPathDebugObjCounterNodeset = 0;
1387 xmlXPathDebugObjCounterBool = 0;
1388 xmlXPathDebugObjCounterNumber = 0;
1389 xmlXPathDebugObjCounterString = 0;
1390 xmlXPathDebugObjCounterPoint = 0;
1391 xmlXPathDebugObjCounterRange = 0;
1392 xmlXPathDebugObjCounterLocset = 0;
1393 xmlXPathDebugObjCounterUsers = 0;
1394 xmlXPathDebugObjCounterXSLTTree = 0;
1395 xmlXPathDebugObjCounterAll = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001396
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001397 xmlXPathDebugObjTotalUndefined = 0;
1398 xmlXPathDebugObjTotalNodeset = 0;
1399 xmlXPathDebugObjTotalBool = 0;
1400 xmlXPathDebugObjTotalNumber = 0;
1401 xmlXPathDebugObjTotalString = 0;
1402 xmlXPathDebugObjTotalPoint = 0;
1403 xmlXPathDebugObjTotalRange = 0;
1404 xmlXPathDebugObjTotalLocset = 0;
1405 xmlXPathDebugObjTotalUsers = 0;
1406 xmlXPathDebugObjTotalXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001407 xmlXPathDebugObjTotalAll = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001408
1409 xmlXPathDebugObjMaxUndefined = 0;
1410 xmlXPathDebugObjMaxNodeset = 0;
1411 xmlXPathDebugObjMaxBool = 0;
1412 xmlXPathDebugObjMaxNumber = 0;
1413 xmlXPathDebugObjMaxString = 0;
1414 xmlXPathDebugObjMaxPoint = 0;
1415 xmlXPathDebugObjMaxRange = 0;
1416 xmlXPathDebugObjMaxLocset = 0;
1417 xmlXPathDebugObjMaxUsers = 0;
1418 xmlXPathDebugObjMaxXSLTTree = 0;
1419 xmlXPathDebugObjMaxAll = 0;
1420
1421}
1422
1423static void
1424xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1425 xmlXPathObjectType objType)
1426{
1427 int isCached = 0;
1428
1429 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001430 if (ctxt->cache != NULL) {
1431 xmlXPathContextCachePtr cache =
1432 (xmlXPathContextCachePtr) ctxt->cache;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001433
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001434 isCached = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001435
1436 cache->dbgReusedAll++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001437 switch (objType) {
1438 case XPATH_UNDEFINED:
1439 cache->dbgReusedUndefined++;
1440 break;
1441 case XPATH_NODESET:
1442 cache->dbgReusedNodeset++;
1443 break;
1444 case XPATH_BOOLEAN:
1445 cache->dbgReusedBool++;
1446 break;
1447 case XPATH_NUMBER:
1448 cache->dbgReusedNumber++;
1449 break;
1450 case XPATH_STRING:
1451 cache->dbgReusedString++;
1452 break;
1453 case XPATH_POINT:
1454 cache->dbgReusedPoint++;
1455 break;
1456 case XPATH_RANGE:
1457 cache->dbgReusedRange++;
1458 break;
1459 case XPATH_LOCATIONSET:
1460 cache->dbgReusedLocset++;
1461 break;
1462 case XPATH_USERS:
1463 cache->dbgReusedUsers++;
1464 break;
1465 case XPATH_XSLT_TREE:
1466 cache->dbgReusedXSLTTree++;
1467 break;
1468 default:
1469 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001470 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001471 }
1472 }
1473
1474 switch (objType) {
1475 case XPATH_UNDEFINED:
1476 if (! isCached)
1477 xmlXPathDebugObjTotalUndefined++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001478 xmlXPathDebugObjCounterUndefined++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001479 if (xmlXPathDebugObjCounterUndefined >
1480 xmlXPathDebugObjMaxUndefined)
1481 xmlXPathDebugObjMaxUndefined =
1482 xmlXPathDebugObjCounterUndefined;
1483 break;
1484 case XPATH_NODESET:
1485 if (! isCached)
1486 xmlXPathDebugObjTotalNodeset++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001487 xmlXPathDebugObjCounterNodeset++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001488 if (xmlXPathDebugObjCounterNodeset >
1489 xmlXPathDebugObjMaxNodeset)
1490 xmlXPathDebugObjMaxNodeset =
1491 xmlXPathDebugObjCounterNodeset;
1492 break;
1493 case XPATH_BOOLEAN:
1494 if (! isCached)
1495 xmlXPathDebugObjTotalBool++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001496 xmlXPathDebugObjCounterBool++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001497 if (xmlXPathDebugObjCounterBool >
1498 xmlXPathDebugObjMaxBool)
1499 xmlXPathDebugObjMaxBool =
1500 xmlXPathDebugObjCounterBool;
1501 break;
1502 case XPATH_NUMBER:
1503 if (! isCached)
1504 xmlXPathDebugObjTotalNumber++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001505 xmlXPathDebugObjCounterNumber++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001506 if (xmlXPathDebugObjCounterNumber >
1507 xmlXPathDebugObjMaxNumber)
1508 xmlXPathDebugObjMaxNumber =
1509 xmlXPathDebugObjCounterNumber;
1510 break;
1511 case XPATH_STRING:
1512 if (! isCached)
1513 xmlXPathDebugObjTotalString++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001514 xmlXPathDebugObjCounterString++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001515 if (xmlXPathDebugObjCounterString >
1516 xmlXPathDebugObjMaxString)
1517 xmlXPathDebugObjMaxString =
1518 xmlXPathDebugObjCounterString;
1519 break;
1520 case XPATH_POINT:
1521 if (! isCached)
1522 xmlXPathDebugObjTotalPoint++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001523 xmlXPathDebugObjCounterPoint++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001524 if (xmlXPathDebugObjCounterPoint >
1525 xmlXPathDebugObjMaxPoint)
1526 xmlXPathDebugObjMaxPoint =
1527 xmlXPathDebugObjCounterPoint;
1528 break;
1529 case XPATH_RANGE:
1530 if (! isCached)
1531 xmlXPathDebugObjTotalRange++;
1532 xmlXPathDebugObjCounterRange++;
1533 if (xmlXPathDebugObjCounterRange >
1534 xmlXPathDebugObjMaxRange)
1535 xmlXPathDebugObjMaxRange =
1536 xmlXPathDebugObjCounterRange;
1537 break;
1538 case XPATH_LOCATIONSET:
1539 if (! isCached)
1540 xmlXPathDebugObjTotalLocset++;
1541 xmlXPathDebugObjCounterLocset++;
1542 if (xmlXPathDebugObjCounterLocset >
1543 xmlXPathDebugObjMaxLocset)
1544 xmlXPathDebugObjMaxLocset =
1545 xmlXPathDebugObjCounterLocset;
1546 break;
1547 case XPATH_USERS:
1548 if (! isCached)
1549 xmlXPathDebugObjTotalUsers++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001550 xmlXPathDebugObjCounterUsers++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001551 if (xmlXPathDebugObjCounterUsers >
1552 xmlXPathDebugObjMaxUsers)
1553 xmlXPathDebugObjMaxUsers =
1554 xmlXPathDebugObjCounterUsers;
1555 break;
1556 case XPATH_XSLT_TREE:
1557 if (! isCached)
1558 xmlXPathDebugObjTotalXSLTTree++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001559 xmlXPathDebugObjCounterXSLTTree++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001560 if (xmlXPathDebugObjCounterXSLTTree >
1561 xmlXPathDebugObjMaxXSLTTree)
1562 xmlXPathDebugObjMaxXSLTTree =
1563 xmlXPathDebugObjCounterXSLTTree;
1564 break;
1565 default:
1566 break;
1567 }
1568 if (! isCached)
1569 xmlXPathDebugObjTotalAll++;
1570 xmlXPathDebugObjCounterAll++;
1571 if (xmlXPathDebugObjCounterAll >
1572 xmlXPathDebugObjMaxAll)
1573 xmlXPathDebugObjMaxAll =
1574 xmlXPathDebugObjCounterAll;
1575}
1576
1577static void
1578xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1579 xmlXPathObjectType objType)
1580{
1581 int isCached = 0;
1582
1583 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001584 if (ctxt->cache != NULL) {
1585 xmlXPathContextCachePtr cache =
1586 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001587
Daniel Veillard45490ae2008-07-29 09:13:19 +00001588 isCached = 1;
1589
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001590 cache->dbgCachedAll++;
1591 switch (objType) {
1592 case XPATH_UNDEFINED:
1593 cache->dbgCachedUndefined++;
1594 break;
1595 case XPATH_NODESET:
1596 cache->dbgCachedNodeset++;
1597 break;
1598 case XPATH_BOOLEAN:
1599 cache->dbgCachedBool++;
1600 break;
1601 case XPATH_NUMBER:
1602 cache->dbgCachedNumber++;
1603 break;
1604 case XPATH_STRING:
1605 cache->dbgCachedString++;
1606 break;
1607 case XPATH_POINT:
1608 cache->dbgCachedPoint++;
1609 break;
1610 case XPATH_RANGE:
1611 cache->dbgCachedRange++;
1612 break;
1613 case XPATH_LOCATIONSET:
1614 cache->dbgCachedLocset++;
1615 break;
1616 case XPATH_USERS:
1617 cache->dbgCachedUsers++;
1618 break;
1619 case XPATH_XSLT_TREE:
1620 cache->dbgCachedXSLTTree++;
1621 break;
1622 default:
1623 break;
1624 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00001625
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001626 }
1627 }
1628 switch (objType) {
1629 case XPATH_UNDEFINED:
1630 xmlXPathDebugObjCounterUndefined--;
1631 break;
1632 case XPATH_NODESET:
1633 xmlXPathDebugObjCounterNodeset--;
1634 break;
1635 case XPATH_BOOLEAN:
1636 xmlXPathDebugObjCounterBool--;
1637 break;
1638 case XPATH_NUMBER:
1639 xmlXPathDebugObjCounterNumber--;
1640 break;
1641 case XPATH_STRING:
1642 xmlXPathDebugObjCounterString--;
1643 break;
1644 case XPATH_POINT:
1645 xmlXPathDebugObjCounterPoint--;
1646 break;
1647 case XPATH_RANGE:
1648 xmlXPathDebugObjCounterRange--;
1649 break;
1650 case XPATH_LOCATIONSET:
1651 xmlXPathDebugObjCounterLocset--;
1652 break;
1653 case XPATH_USERS:
1654 xmlXPathDebugObjCounterUsers--;
1655 break;
1656 case XPATH_XSLT_TREE:
1657 xmlXPathDebugObjCounterXSLTTree--;
1658 break;
1659 default:
1660 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001661 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001662 xmlXPathDebugObjCounterAll--;
1663}
1664
1665/* REVISIT TODO: Make this static when committing */
1666static void
1667xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
1668{
1669 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
1670 reqXSLTTree, reqUndefined;
1671 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
1672 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
1673 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
1674 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
1675 int leftObjs = xmlXPathDebugObjCounterAll;
1676
1677 reqAll = xmlXPathDebugObjTotalAll;
1678 reqNodeset = xmlXPathDebugObjTotalNodeset;
1679 reqString = xmlXPathDebugObjTotalString;
1680 reqBool = xmlXPathDebugObjTotalBool;
1681 reqNumber = xmlXPathDebugObjTotalNumber;
1682 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
1683 reqUndefined = xmlXPathDebugObjTotalUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001684
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001685 printf("# XPath object usage:\n");
1686
1687 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001688 if (ctxt->cache != NULL) {
1689 xmlXPathContextCachePtr cache =
1690 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001691
1692 reAll = cache->dbgReusedAll;
1693 reqAll += reAll;
1694 reNodeset = cache->dbgReusedNodeset;
1695 reqNodeset += reNodeset;
1696 reString = cache->dbgReusedString;
1697 reqString += reString;
1698 reBool = cache->dbgReusedBool;
1699 reqBool += reBool;
1700 reNumber = cache->dbgReusedNumber;
1701 reqNumber += reNumber;
1702 reXSLTTree = cache->dbgReusedXSLTTree;
1703 reqXSLTTree += reXSLTTree;
1704 reUndefined = cache->dbgReusedUndefined;
1705 reqUndefined += reUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001706
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001707 caAll = cache->dbgCachedAll;
1708 caBool = cache->dbgCachedBool;
1709 caNodeset = cache->dbgCachedNodeset;
1710 caString = cache->dbgCachedString;
1711 caNumber = cache->dbgCachedNumber;
1712 caXSLTTree = cache->dbgCachedXSLTTree;
1713 caUndefined = cache->dbgCachedUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001714
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001715 if (cache->nodesetObjs)
1716 leftObjs -= cache->nodesetObjs->number;
1717 if (cache->stringObjs)
1718 leftObjs -= cache->stringObjs->number;
1719 if (cache->booleanObjs)
1720 leftObjs -= cache->booleanObjs->number;
1721 if (cache->numberObjs)
1722 leftObjs -= cache->numberObjs->number;
1723 if (cache->miscObjs)
1724 leftObjs -= cache->miscObjs->number;
1725 }
1726 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00001727
1728 printf("# all\n");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001729 printf("# total : %d\n", reqAll);
1730 printf("# left : %d\n", leftObjs);
1731 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
1732 printf("# reused : %d\n", reAll);
1733 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
1734
1735 printf("# node-sets\n");
1736 printf("# total : %d\n", reqNodeset);
1737 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
1738 printf("# reused : %d\n", reNodeset);
1739 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
1740
1741 printf("# strings\n");
1742 printf("# total : %d\n", reqString);
1743 printf("# created: %d\n", xmlXPathDebugObjTotalString);
1744 printf("# reused : %d\n", reString);
1745 printf("# max : %d\n", xmlXPathDebugObjMaxString);
1746
1747 printf("# booleans\n");
1748 printf("# total : %d\n", reqBool);
1749 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
1750 printf("# reused : %d\n", reBool);
1751 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
1752
1753 printf("# numbers\n");
1754 printf("# total : %d\n", reqNumber);
1755 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
1756 printf("# reused : %d\n", reNumber);
1757 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
1758
1759 printf("# XSLT result tree fragments\n");
1760 printf("# total : %d\n", reqXSLTTree);
1761 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
1762 printf("# reused : %d\n", reXSLTTree);
1763 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
1764
1765 printf("# undefined\n");
1766 printf("# total : %d\n", reqUndefined);
1767 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
1768 printf("# reused : %d\n", reUndefined);
1769 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
1770
1771}
1772
1773#endif /* XP_DEBUG_OBJ_USAGE */
1774
Daniel Veillard017b1082001-06-21 11:20:21 +00001775#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001776
1777/************************************************************************
1778 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001779 * XPath object caching *
1780 * *
1781 ************************************************************************/
1782
1783/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001784 * xmlXPathNewCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001785 *
1786 * Create a new object cache
1787 *
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001788 * Returns the xmlXPathCache just allocated.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001789 */
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001790static xmlXPathContextCachePtr
1791xmlXPathNewCache(void)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001792{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001793 xmlXPathContextCachePtr ret;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001794
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001795 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001796 if (ret == NULL) {
1797 xmlXPathErrMemory(NULL, "creating object cache\n");
1798 return(NULL);
1799 }
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001800 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001801 ret->maxNodeset = 100;
1802 ret->maxString = 100;
1803 ret->maxBoolean = 100;
1804 ret->maxNumber = 100;
1805 ret->maxMisc = 100;
1806 return(ret);
1807}
1808
1809static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001810xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001811{
1812 int i;
1813 xmlXPathObjectPtr obj;
1814
1815 if (list == NULL)
1816 return;
1817
1818 for (i = 0; i < list->number; i++) {
1819 obj = list->items[i];
1820 /*
1821 * Note that it is already assured that we don't need to
1822 * look out for namespace nodes in the node-set.
1823 */
1824 if (obj->nodesetval != NULL) {
1825 if (obj->nodesetval->nodeTab != NULL)
1826 xmlFree(obj->nodesetval->nodeTab);
1827 xmlFree(obj->nodesetval);
1828 }
1829 xmlFree(obj);
1830#ifdef XP_DEBUG_OBJ_USAGE
1831 xmlXPathDebugObjCounterAll--;
1832#endif
1833 }
1834 xmlPointerListFree(list);
1835}
1836
1837static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001838xmlXPathFreeCache(xmlXPathContextCachePtr cache)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001839{
1840 if (cache == NULL)
1841 return;
1842 if (cache->nodesetObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001843 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001844 if (cache->stringObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001845 xmlXPathCacheFreeObjectList(cache->stringObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001846 if (cache->booleanObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001847 xmlXPathCacheFreeObjectList(cache->booleanObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001848 if (cache->numberObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001849 xmlXPathCacheFreeObjectList(cache->numberObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001850 if (cache->miscObjs)
Daniel Veillard45490ae2008-07-29 09:13:19 +00001851 xmlXPathCacheFreeObjectList(cache->miscObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001852 xmlFree(cache);
1853}
1854
1855/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001856 * xmlXPathContextSetCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001857 *
1858 * @ctxt: the XPath context
1859 * @active: enables/disables (creates/frees) the cache
Daniel Veillard45490ae2008-07-29 09:13:19 +00001860 * @value: a value with semantics dependant on @options
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001861 * @options: options (currently only the value 0 is used)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001862 *
1863 * Creates/frees an object cache on the XPath context.
1864 * If activates XPath objects (xmlXPathObject) will be cached internally
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001865 * to be reused.
1866 * @options:
1867 * 0: This will set the XPath object caching:
1868 * @value:
1869 * This will set the maximum number of XPath objects
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001870 * to be cached per slot
1871 * There are 5 slots for: node-set, string, number, boolean, and
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001872 * misc objects. Use <0 for the default number (100).
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001873 * Other values for @options have currently no effect.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001874 *
1875 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1876 */
1877int
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001878xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1879 int active,
1880 int value,
1881 int options)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001882{
1883 if (ctxt == NULL)
1884 return(-1);
1885 if (active) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001886 xmlXPathContextCachePtr cache;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001887
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001888 if (ctxt->cache == NULL) {
1889 ctxt->cache = xmlXPathNewCache();
1890 if (ctxt->cache == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001891 return(-1);
1892 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001893 cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001894 if (options == 0) {
1895 if (value < 0)
1896 value = 100;
1897 cache->maxNodeset = value;
1898 cache->maxString = value;
1899 cache->maxNumber = value;
1900 cache->maxBoolean = value;
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001901 cache->maxMisc = value;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001902 }
1903 } else if (ctxt->cache != NULL) {
1904 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1905 ctxt->cache = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001906 }
1907 return(0);
1908}
1909
1910/**
1911 * xmlXPathCacheWrapNodeSet:
1912 * @ctxt: the XPath context
1913 * @val: the NodePtr value
1914 *
1915 * This is the cached version of xmlXPathWrapNodeSet().
1916 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1917 *
1918 * Returns the created or reused object.
1919 */
1920static xmlXPathObjectPtr
1921xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00001922{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001923 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1924 xmlXPathContextCachePtr cache =
1925 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001926
1927 if ((cache->miscObjs != NULL) &&
1928 (cache->miscObjs->number != 0))
1929 {
1930 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001931
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001932 ret = (xmlXPathObjectPtr)
1933 cache->miscObjs->items[--cache->miscObjs->number];
1934 ret->type = XPATH_NODESET;
1935 ret->nodesetval = val;
1936#ifdef XP_DEBUG_OBJ_USAGE
1937 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
1938#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00001939 return(ret);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001940 }
1941 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00001942
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001943 return(xmlXPathWrapNodeSet(val));
Daniel Veillard45490ae2008-07-29 09:13:19 +00001944
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001945}
1946
1947/**
1948 * xmlXPathCacheWrapString:
1949 * @ctxt: the XPath context
1950 * @val: the xmlChar * value
1951 *
1952 * This is the cached version of xmlXPathWrapString().
1953 * Wraps the @val string into an XPath object.
1954 *
1955 * Returns the created or reused object.
1956 */
1957static xmlXPathObjectPtr
1958xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00001959{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001960 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1961 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001962
1963 if ((cache->stringObjs != NULL) &&
1964 (cache->stringObjs->number != 0))
1965 {
Daniel Veillard45490ae2008-07-29 09:13:19 +00001966
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001967 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001968
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001969 ret = (xmlXPathObjectPtr)
1970 cache->stringObjs->items[--cache->stringObjs->number];
1971 ret->type = XPATH_STRING;
1972 ret->stringval = val;
1973#ifdef XP_DEBUG_OBJ_USAGE
1974 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1975#endif
1976 return(ret);
1977 } else if ((cache->miscObjs != NULL) &&
1978 (cache->miscObjs->number != 0))
1979 {
1980 xmlXPathObjectPtr ret;
1981 /*
1982 * Fallback to misc-cache.
1983 */
1984 ret = (xmlXPathObjectPtr)
1985 cache->miscObjs->items[--cache->miscObjs->number];
1986
1987 ret->type = XPATH_STRING;
1988 ret->stringval = val;
1989#ifdef XP_DEBUG_OBJ_USAGE
1990 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1991#endif
1992 return(ret);
1993 }
1994 }
1995 return(xmlXPathWrapString(val));
1996}
1997
1998/**
1999 * xmlXPathCacheNewNodeSet:
2000 * @ctxt: the XPath context
2001 * @val: the NodePtr value
2002 *
2003 * This is the cached version of xmlXPathNewNodeSet().
2004 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2005 * it with the single Node @val
2006 *
2007 * Returns the created or reused object.
2008 */
2009static xmlXPathObjectPtr
2010xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2011{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002012 if ((ctxt != NULL) && (ctxt->cache)) {
2013 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002014
2015 if ((cache->nodesetObjs != NULL) &&
2016 (cache->nodesetObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002017 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002018 xmlXPathObjectPtr ret;
2019 /*
2020 * Use the nodset-cache.
Daniel Veillard45490ae2008-07-29 09:13:19 +00002021 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002022 ret = (xmlXPathObjectPtr)
2023 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2024 ret->type = XPATH_NODESET;
2025 ret->boolval = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002026 if (val) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002027 if ((ret->nodesetval->nodeMax == 0) ||
2028 (val->type == XML_NAMESPACE_DECL))
2029 {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002030 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002031 } else {
2032 ret->nodesetval->nodeTab[0] = val;
2033 ret->nodesetval->nodeNr = 1;
2034 }
2035 }
2036#ifdef XP_DEBUG_OBJ_USAGE
2037 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2038#endif
2039 return(ret);
2040 } else if ((cache->miscObjs != NULL) &&
2041 (cache->miscObjs->number != 0))
2042 {
2043 xmlXPathObjectPtr ret;
2044 /*
2045 * Fallback to misc-cache.
2046 */
2047
2048 ret = (xmlXPathObjectPtr)
2049 cache->miscObjs->items[--cache->miscObjs->number];
2050
2051 ret->type = XPATH_NODESET;
2052 ret->boolval = 0;
2053 ret->nodesetval = xmlXPathNodeSetCreate(val);
2054#ifdef XP_DEBUG_OBJ_USAGE
2055 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2056#endif
2057 return(ret);
2058 }
2059 }
2060 return(xmlXPathNewNodeSet(val));
2061}
2062
2063/**
2064 * xmlXPathCacheNewCString:
2065 * @ctxt: the XPath context
2066 * @val: the char * value
2067 *
2068 * This is the cached version of xmlXPathNewCString().
2069 * Acquire an xmlXPathObjectPtr of type string and of value @val
2070 *
2071 * Returns the created or reused object.
2072 */
2073static xmlXPathObjectPtr
2074xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002075{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002076 if ((ctxt != NULL) && (ctxt->cache)) {
2077 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002078
2079 if ((cache->stringObjs != NULL) &&
2080 (cache->stringObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002081 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002082 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002083
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002084 ret = (xmlXPathObjectPtr)
2085 cache->stringObjs->items[--cache->stringObjs->number];
2086
2087 ret->type = XPATH_STRING;
2088 ret->stringval = xmlStrdup(BAD_CAST val);
2089#ifdef XP_DEBUG_OBJ_USAGE
2090 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2091#endif
2092 return(ret);
2093 } else if ((cache->miscObjs != NULL) &&
2094 (cache->miscObjs->number != 0))
2095 {
2096 xmlXPathObjectPtr ret;
2097
2098 ret = (xmlXPathObjectPtr)
2099 cache->miscObjs->items[--cache->miscObjs->number];
2100
2101 ret->type = XPATH_STRING;
2102 ret->stringval = xmlStrdup(BAD_CAST val);
2103#ifdef XP_DEBUG_OBJ_USAGE
2104 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2105#endif
2106 return(ret);
2107 }
2108 }
2109 return(xmlXPathNewCString(val));
2110}
2111
2112/**
2113 * xmlXPathCacheNewString:
2114 * @ctxt: the XPath context
2115 * @val: the xmlChar * value
2116 *
2117 * This is the cached version of xmlXPathNewString().
2118 * Acquire an xmlXPathObjectPtr of type string and of value @val
2119 *
2120 * Returns the created or reused object.
2121 */
2122static xmlXPathObjectPtr
2123xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002124{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002125 if ((ctxt != NULL) && (ctxt->cache)) {
2126 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002127
2128 if ((cache->stringObjs != NULL) &&
2129 (cache->stringObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002130 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002131 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002132
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002133 ret = (xmlXPathObjectPtr)
2134 cache->stringObjs->items[--cache->stringObjs->number];
2135 ret->type = XPATH_STRING;
2136 if (val != NULL)
2137 ret->stringval = xmlStrdup(val);
2138 else
2139 ret->stringval = xmlStrdup((const xmlChar *)"");
2140#ifdef XP_DEBUG_OBJ_USAGE
2141 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2142#endif
2143 return(ret);
2144 } else if ((cache->miscObjs != NULL) &&
2145 (cache->miscObjs->number != 0))
2146 {
2147 xmlXPathObjectPtr ret;
2148
2149 ret = (xmlXPathObjectPtr)
2150 cache->miscObjs->items[--cache->miscObjs->number];
2151
2152 ret->type = XPATH_STRING;
2153 if (val != NULL)
2154 ret->stringval = xmlStrdup(val);
2155 else
2156 ret->stringval = xmlStrdup((const xmlChar *)"");
2157#ifdef XP_DEBUG_OBJ_USAGE
2158 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2159#endif
2160 return(ret);
2161 }
2162 }
2163 return(xmlXPathNewString(val));
2164}
2165
2166/**
2167 * xmlXPathCacheNewBoolean:
2168 * @ctxt: the XPath context
2169 * @val: the boolean value
2170 *
2171 * This is the cached version of xmlXPathNewBoolean().
2172 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2173 *
2174 * Returns the created or reused object.
2175 */
2176static xmlXPathObjectPtr
2177xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002178{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002179 if ((ctxt != NULL) && (ctxt->cache)) {
2180 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002181
2182 if ((cache->booleanObjs != NULL) &&
2183 (cache->booleanObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002184 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002185 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002186
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002187 ret = (xmlXPathObjectPtr)
2188 cache->booleanObjs->items[--cache->booleanObjs->number];
2189 ret->type = XPATH_BOOLEAN;
2190 ret->boolval = (val != 0);
2191#ifdef XP_DEBUG_OBJ_USAGE
2192 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2193#endif
2194 return(ret);
2195 } else if ((cache->miscObjs != NULL) &&
2196 (cache->miscObjs->number != 0))
2197 {
2198 xmlXPathObjectPtr ret;
2199
2200 ret = (xmlXPathObjectPtr)
2201 cache->miscObjs->items[--cache->miscObjs->number];
2202
2203 ret->type = XPATH_BOOLEAN;
2204 ret->boolval = (val != 0);
2205#ifdef XP_DEBUG_OBJ_USAGE
2206 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2207#endif
2208 return(ret);
2209 }
2210 }
2211 return(xmlXPathNewBoolean(val));
2212}
2213
2214/**
2215 * xmlXPathCacheNewFloat:
2216 * @ctxt: the XPath context
2217 * @val: the double value
2218 *
2219 * This is the cached version of xmlXPathNewFloat().
2220 * Acquires an xmlXPathObjectPtr of type double and of value @val
2221 *
2222 * Returns the created or reused object.
2223 */
2224static xmlXPathObjectPtr
2225xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2226{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002227 if ((ctxt != NULL) && (ctxt->cache)) {
2228 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002229
2230 if ((cache->numberObjs != NULL) &&
2231 (cache->numberObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002232 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002233 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002234
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002235 ret = (xmlXPathObjectPtr)
2236 cache->numberObjs->items[--cache->numberObjs->number];
2237 ret->type = XPATH_NUMBER;
2238 ret->floatval = val;
2239#ifdef XP_DEBUG_OBJ_USAGE
2240 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2241#endif
2242 return(ret);
2243 } else if ((cache->miscObjs != NULL) &&
2244 (cache->miscObjs->number != 0))
2245 {
2246 xmlXPathObjectPtr ret;
2247
2248 ret = (xmlXPathObjectPtr)
2249 cache->miscObjs->items[--cache->miscObjs->number];
2250
2251 ret->type = XPATH_NUMBER;
2252 ret->floatval = val;
2253#ifdef XP_DEBUG_OBJ_USAGE
2254 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2255#endif
2256 return(ret);
2257 }
2258 }
2259 return(xmlXPathNewFloat(val));
2260}
2261
2262/**
2263 * xmlXPathCacheConvertString:
2264 * @ctxt: the XPath context
2265 * @val: an XPath object
2266 *
2267 * This is the cached version of xmlXPathConvertString().
2268 * Converts an existing object to its string() equivalent
2269 *
2270 * Returns a created or reused object, the old one is freed (cached)
2271 * (or the operation is done directly on @val)
2272 */
2273
2274static xmlXPathObjectPtr
2275xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002276 xmlChar *res = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002277
2278 if (val == NULL)
2279 return(xmlXPathCacheNewCString(ctxt, ""));
2280
2281 switch (val->type) {
2282 case XPATH_UNDEFINED:
2283#ifdef DEBUG_EXPR
2284 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2285#endif
2286 break;
2287 case XPATH_NODESET:
2288 case XPATH_XSLT_TREE:
2289 res = xmlXPathCastNodeSetToString(val->nodesetval);
2290 break;
2291 case XPATH_STRING:
2292 return(val);
2293 case XPATH_BOOLEAN:
2294 res = xmlXPathCastBooleanToString(val->boolval);
2295 break;
2296 case XPATH_NUMBER:
2297 res = xmlXPathCastNumberToString(val->floatval);
2298 break;
2299 case XPATH_USERS:
2300 case XPATH_POINT:
2301 case XPATH_RANGE:
2302 case XPATH_LOCATIONSET:
2303 TODO;
2304 break;
2305 }
2306 xmlXPathReleaseObject(ctxt, val);
2307 if (res == NULL)
2308 return(xmlXPathCacheNewCString(ctxt, ""));
2309 return(xmlXPathCacheWrapString(ctxt, res));
2310}
2311
2312/**
2313 * xmlXPathCacheObjectCopy:
2314 * @ctxt: the XPath context
2315 * @val: the original object
2316 *
2317 * This is the cached version of xmlXPathObjectCopy().
2318 * Acquire a copy of a given object
2319 *
2320 * Returns a created or reused created object.
2321 */
2322static xmlXPathObjectPtr
2323xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2324{
2325 if (val == NULL)
2326 return(NULL);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002327
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002328 if (XP_HAS_CACHE(ctxt)) {
2329 switch (val->type) {
2330 case XPATH_NODESET:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002331 return(xmlXPathCacheWrapNodeSet(ctxt,
2332 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002333 case XPATH_STRING:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002334 return(xmlXPathCacheNewString(ctxt, val->stringval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002335 case XPATH_BOOLEAN:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002336 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002337 case XPATH_NUMBER:
2338 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2339 default:
2340 break;
2341 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002342 }
2343 return(xmlXPathObjectCopy(val));
2344}
2345
2346/**
2347 * xmlXPathCacheConvertBoolean:
2348 * @ctxt: the XPath context
2349 * @val: an XPath object
2350 *
2351 * This is the cached version of xmlXPathConvertBoolean().
2352 * Converts an existing object to its boolean() equivalent
2353 *
2354 * Returns a created or reused object, the old one is freed (or the operation
2355 * is done directly on @val)
2356 */
2357static xmlXPathObjectPtr
2358xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2359 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002360
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002361 if (val == NULL)
2362 return(xmlXPathCacheNewBoolean(ctxt, 0));
2363 if (val->type == XPATH_BOOLEAN)
2364 return(val);
2365 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2366 xmlXPathReleaseObject(ctxt, val);
2367 return(ret);
2368}
2369
2370/**
2371 * xmlXPathCacheConvertNumber:
2372 * @ctxt: the XPath context
2373 * @val: an XPath object
2374 *
2375 * This is the cached version of xmlXPathConvertNumber().
2376 * Converts an existing object to its number() equivalent
2377 *
2378 * Returns a created or reused object, the old one is freed (or the operation
2379 * is done directly on @val)
2380 */
2381static xmlXPathObjectPtr
2382xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2383 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002384
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002385 if (val == NULL)
2386 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2387 if (val->type == XPATH_NUMBER)
2388 return(val);
2389 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2390 xmlXPathReleaseObject(ctxt, val);
2391 return(ret);
2392}
2393
2394/************************************************************************
2395 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +00002396 * Parser stacks related functions and macros *
Owen Taylor3473f882001-02-23 17:55:21 +00002397 * *
2398 ************************************************************************/
2399
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002400/**
2401 * valuePop:
2402 * @ctxt: an XPath evaluation context
2403 *
2404 * Pops the top XPath object from the value stack
2405 *
2406 * Returns the XPath object just removed
2407 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002408xmlXPathObjectPtr
Daniel Veillard1c732d22002-11-30 11:22:59 +00002409valuePop(xmlXPathParserContextPtr ctxt)
2410{
2411 xmlXPathObjectPtr ret;
2412
Daniel Veillarda82b1822004-11-08 16:24:57 +00002413 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
Daniel Veillard24505b02005-07-28 23:49:35 +00002414 return (NULL);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002415 ctxt->valueNr--;
2416 if (ctxt->valueNr > 0)
2417 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2418 else
2419 ctxt->value = NULL;
2420 ret = ctxt->valueTab[ctxt->valueNr];
Daniel Veillard24505b02005-07-28 23:49:35 +00002421 ctxt->valueTab[ctxt->valueNr] = NULL;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002422 return (ret);
2423}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002424/**
2425 * valuePush:
2426 * @ctxt: an XPath evaluation context
2427 * @value: the XPath object
2428 *
2429 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002430 *
2431 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002432 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002433int
Daniel Veillard1c732d22002-11-30 11:22:59 +00002434valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2435{
Daniel Veillarda82b1822004-11-08 16:24:57 +00002436 if ((ctxt == NULL) || (value == NULL)) return(-1);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002437 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002438 xmlXPathObjectPtr *tmp;
2439
2440 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2441 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00002442 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002443 if (tmp == NULL) {
Daniel Veillard1c732d22002-11-30 11:22:59 +00002444 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
2445 return (0);
2446 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002447 ctxt->valueMax *= 2;
2448 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002449 }
2450 ctxt->valueTab[ctxt->valueNr] = value;
2451 ctxt->value = value;
2452 return (ctxt->valueNr++);
2453}
Owen Taylor3473f882001-02-23 17:55:21 +00002454
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002455/**
2456 * xmlXPathPopBoolean:
2457 * @ctxt: an XPath parser context
2458 *
2459 * Pops a boolean from the stack, handling conversion if needed.
2460 * Check error with #xmlXPathCheckError.
2461 *
2462 * Returns the boolean
2463 */
2464int
2465xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2466 xmlXPathObjectPtr obj;
2467 int ret;
2468
2469 obj = valuePop(ctxt);
2470 if (obj == NULL) {
2471 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2472 return(0);
2473 }
William M. Brack08171912003-12-29 02:52:11 +00002474 if (obj->type != XPATH_BOOLEAN)
2475 ret = xmlXPathCastToBoolean(obj);
2476 else
2477 ret = obj->boolval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002478 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002479 return(ret);
2480}
2481
2482/**
2483 * xmlXPathPopNumber:
2484 * @ctxt: an XPath parser context
2485 *
2486 * Pops a number from the stack, handling conversion if needed.
2487 * Check error with #xmlXPathCheckError.
2488 *
2489 * Returns the number
2490 */
2491double
2492xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2493 xmlXPathObjectPtr obj;
2494 double ret;
2495
2496 obj = valuePop(ctxt);
2497 if (obj == NULL) {
2498 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2499 return(0);
2500 }
William M. Brack08171912003-12-29 02:52:11 +00002501 if (obj->type != XPATH_NUMBER)
2502 ret = xmlXPathCastToNumber(obj);
2503 else
2504 ret = obj->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002505 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002506 return(ret);
2507}
2508
2509/**
2510 * xmlXPathPopString:
2511 * @ctxt: an XPath parser context
2512 *
2513 * Pops a string from the stack, handling conversion if needed.
2514 * Check error with #xmlXPathCheckError.
2515 *
2516 * Returns the string
2517 */
2518xmlChar *
2519xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2520 xmlXPathObjectPtr obj;
2521 xmlChar * ret;
2522
2523 obj = valuePop(ctxt);
2524 if (obj == NULL) {
2525 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2526 return(NULL);
2527 }
William M. Brack08171912003-12-29 02:52:11 +00002528 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002529 /* TODO: needs refactoring somewhere else */
2530 if (obj->stringval == ret)
2531 obj->stringval = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002532 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002533 return(ret);
2534}
2535
2536/**
2537 * xmlXPathPopNodeSet:
2538 * @ctxt: an XPath parser context
2539 *
2540 * Pops a node-set from the stack, handling conversion if needed.
2541 * Check error with #xmlXPathCheckError.
2542 *
2543 * Returns the node-set
2544 */
2545xmlNodeSetPtr
2546xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2547 xmlXPathObjectPtr obj;
2548 xmlNodeSetPtr ret;
2549
Daniel Veillardf2a36f92004-11-08 17:55:01 +00002550 if (ctxt == NULL) return(NULL);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002551 if (ctxt->value == NULL) {
2552 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2553 return(NULL);
2554 }
2555 if (!xmlXPathStackIsNodeSet(ctxt)) {
2556 xmlXPathSetTypeError(ctxt);
2557 return(NULL);
2558 }
2559 obj = valuePop(ctxt);
2560 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00002561#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00002562 /* to fix memory leak of not clearing obj->user */
2563 if (obj->boolval && obj->user != NULL)
2564 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00002565#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002566 obj->nodesetval = NULL;
2567 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002568 return(ret);
2569}
2570
2571/**
2572 * xmlXPathPopExternal:
2573 * @ctxt: an XPath parser context
2574 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002575 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002576 * Check error with #xmlXPathCheckError.
2577 *
2578 * Returns the object
2579 */
2580void *
2581xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2582 xmlXPathObjectPtr obj;
2583 void * ret;
2584
Daniel Veillarda82b1822004-11-08 16:24:57 +00002585 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002586 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2587 return(NULL);
2588 }
2589 if (ctxt->value->type != XPATH_USERS) {
2590 xmlXPathSetTypeError(ctxt);
2591 return(NULL);
2592 }
2593 obj = valuePop(ctxt);
2594 ret = obj->user;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002595 obj->user = NULL;
2596 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002597 return(ret);
2598}
2599
Owen Taylor3473f882001-02-23 17:55:21 +00002600/*
2601 * Macros for accessing the content. Those should be used only by the parser,
2602 * and not exported.
2603 *
2604 * Dirty macros, i.e. one need to make assumption on the context to use them
2605 *
2606 * CUR_PTR return the current pointer to the xmlChar to be parsed.
2607 * CUR returns the current xmlChar value, i.e. a 8 bit value
2608 * in ISO-Latin or UTF-8.
2609 * This should be used internally by the parser
2610 * only to compare to ASCII values otherwise it would break when
2611 * running with UTF-8 encoding.
2612 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
2613 * to compare on ASCII based substring.
2614 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2615 * strings within the parser.
2616 * CURRENT Returns the current char value, with the full decoding of
2617 * UTF-8 if we are using this mode. It returns an int.
2618 * NEXT Skip to the next character, this does the proper decoding
2619 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
2620 * It returns the pointer to the current xmlChar.
2621 */
2622
2623#define CUR (*ctxt->cur)
2624#define SKIP(val) ctxt->cur += (val)
2625#define NXT(val) ctxt->cur[(val)]
2626#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00002627#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2628
2629#define COPY_BUF(l,b,i,v) \
2630 if (l == 1) b[i++] = (xmlChar) v; \
2631 else i += xmlCopyChar(l,&b[i],v)
2632
2633#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00002634
Daniel Veillard45490ae2008-07-29 09:13:19 +00002635#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00002636 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00002637
2638#define CURRENT (*ctxt->cur)
2639#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
2640
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002641
2642#ifndef DBL_DIG
2643#define DBL_DIG 16
2644#endif
2645#ifndef DBL_EPSILON
2646#define DBL_EPSILON 1E-9
2647#endif
2648
2649#define UPPER_DOUBLE 1E9
2650#define LOWER_DOUBLE 1E-5
William M. Brackca797882007-05-11 14:45:53 +00002651#define LOWER_DOUBLE_EXP 5
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002652
2653#define INTEGER_DIGITS DBL_DIG
William M. Brackca797882007-05-11 14:45:53 +00002654#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002655#define EXPONENT_DIGITS (3 + 2)
2656
2657/**
2658 * xmlXPathFormatNumber:
2659 * @number: number to format
2660 * @buffer: output buffer
2661 * @buffersize: size of output buffer
2662 *
2663 * Convert the number into a string representation.
2664 */
2665static void
2666xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2667{
Daniel Veillardcda96922001-08-21 10:56:31 +00002668 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002669 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00002670 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002671 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002672 break;
2673 case -1:
2674 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002675 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002676 break;
2677 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00002678 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002679 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002680 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00002681 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002682 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002683 } else if (number == ((int) number)) {
2684 char work[30];
2685 char *ptr, *cur;
Daniel Veillardb3d14912005-09-04 20:47:39 +00002686 int value = (int) number;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002687
2688 ptr = &buffer[0];
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002689 if (value == 0) {
2690 *ptr++ = '0';
2691 } else {
Daniel Veillardb3d14912005-09-04 20:47:39 +00002692 snprintf(work, 29, "%d", value);
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002693 cur = &work[0];
Daniel Veillardb3d14912005-09-04 20:47:39 +00002694 while ((*cur) && (ptr - buffer < buffersize)) {
2695 *ptr++ = *cur++;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002696 }
2697 }
2698 if (ptr - buffer < buffersize) {
2699 *ptr = 0;
2700 } else if (buffersize > 0) {
2701 ptr--;
2702 *ptr = 0;
2703 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002704 } else {
William M. Brackca797882007-05-11 14:45:53 +00002705 /*
2706 For the dimension of work,
2707 DBL_DIG is number of significant digits
2708 EXPONENT is only needed for "scientific notation"
2709 3 is sign, decimal point, and terminating zero
2710 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2711 Note that this dimension is slightly (a few characters)
2712 larger than actually necessary.
2713 */
2714 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
Bjorn Reese70a9da52001-04-21 16:57:29 +00002715 int integer_place, fraction_place;
2716 char *ptr;
2717 char *after_fraction;
2718 double absolute_value;
2719 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002720
Bjorn Reese70a9da52001-04-21 16:57:29 +00002721 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002722
Bjorn Reese70a9da52001-04-21 16:57:29 +00002723 /*
2724 * First choose format - scientific or regular floating point.
2725 * In either case, result is in work, and after_fraction points
2726 * just past the fractional part.
2727 */
2728 if ( ((absolute_value > UPPER_DOUBLE) ||
2729 (absolute_value < LOWER_DOUBLE)) &&
2730 (absolute_value != 0.0) ) {
2731 /* Use scientific notation */
2732 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2733 fraction_place = DBL_DIG - 1;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002734 size = snprintf(work, sizeof(work),"%*.*e",
Bjorn Reese70a9da52001-04-21 16:57:29 +00002735 integer_place, fraction_place, number);
Daniel Veillard11ce4002006-03-10 00:36:23 +00002736 while ((size > 0) && (work[size] != 'e')) size--;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002737
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002738 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002739 else {
2740 /* Use regular notation */
William M. Brackca797882007-05-11 14:45:53 +00002741 if (absolute_value > 0.0) {
2742 integer_place = (int)log10(absolute_value);
2743 if (integer_place > 0)
2744 fraction_place = DBL_DIG - integer_place - 1;
2745 else
2746 fraction_place = DBL_DIG - integer_place;
2747 } else {
2748 fraction_place = 1;
2749 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002750 size = snprintf(work, sizeof(work), "%0.*f",
2751 fraction_place, number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002752 }
2753
Bjorn Reese70a9da52001-04-21 16:57:29 +00002754 /* Remove fractional trailing zeroes */
William M. Brackca797882007-05-11 14:45:53 +00002755 after_fraction = work + size;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002756 ptr = after_fraction;
2757 while (*(--ptr) == '0')
2758 ;
2759 if (*ptr != '.')
2760 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002761 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002762
2763 /* Finally copy result back to caller */
2764 size = strlen(work) + 1;
2765 if (size > buffersize) {
2766 work[buffersize - 1] = 0;
2767 size = buffersize;
2768 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002769 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002770 }
2771 break;
2772 }
2773}
2774
Owen Taylor3473f882001-02-23 17:55:21 +00002775
2776/************************************************************************
2777 * *
2778 * Routines to handle NodeSets *
2779 * *
2780 ************************************************************************/
2781
2782/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002783 * xmlXPathOrderDocElems:
2784 * @doc: an input document
2785 *
2786 * Call this routine to speed up XPath computation on static documents.
2787 * This stamps all the element nodes with the document order
2788 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00002789 * field, the value stored is actually - the node number (starting at -1)
2790 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002791 *
William M. Brack08171912003-12-29 02:52:11 +00002792 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002793 * of error.
2794 */
2795long
2796xmlXPathOrderDocElems(xmlDocPtr doc) {
2797 long count = 0;
2798 xmlNodePtr cur;
2799
2800 if (doc == NULL)
2801 return(-1);
2802 cur = doc->children;
2803 while (cur != NULL) {
2804 if (cur->type == XML_ELEMENT_NODE) {
2805 cur->content = (void *) (-(++count));
2806 if (cur->children != NULL) {
2807 cur = cur->children;
2808 continue;
2809 }
2810 }
2811 if (cur->next != NULL) {
2812 cur = cur->next;
2813 continue;
2814 }
2815 do {
2816 cur = cur->parent;
2817 if (cur == NULL)
2818 break;
2819 if (cur == (xmlNodePtr) doc) {
2820 cur = NULL;
2821 break;
2822 }
2823 if (cur->next != NULL) {
2824 cur = cur->next;
2825 break;
2826 }
2827 } while (cur != NULL);
2828 }
2829 return(count);
2830}
2831
2832/**
Owen Taylor3473f882001-02-23 17:55:21 +00002833 * xmlXPathCmpNodes:
2834 * @node1: the first node
2835 * @node2: the second node
2836 *
2837 * Compare two nodes w.r.t document order
2838 *
2839 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00002840 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00002841 */
2842int
2843xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2844 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002845 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002846 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002847 xmlNodePtr cur, root;
2848
2849 if ((node1 == NULL) || (node2 == NULL))
2850 return(-2);
2851 /*
2852 * a couple of optimizations which will avoid computations in most cases
2853 */
William M. Brackee0b9822007-03-07 08:15:01 +00002854 if (node1 == node2) /* trivial case */
2855 return(0);
Daniel Veillardedfd5882003-03-07 14:20:40 +00002856 if (node1->type == XML_ATTRIBUTE_NODE) {
2857 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002858 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002859 node1 = node1->parent;
2860 }
2861 if (node2->type == XML_ATTRIBUTE_NODE) {
2862 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002863 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002864 node2 = node2->parent;
2865 }
2866 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00002867 if (attr1 == attr2) {
2868 /* not required, but we keep attributes in order */
2869 if (attr1 != 0) {
2870 cur = attrNode2->prev;
2871 while (cur != NULL) {
2872 if (cur == attrNode1)
2873 return (1);
2874 cur = cur->prev;
2875 }
2876 return (-1);
2877 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00002878 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00002879 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00002880 if (attr2 == 1)
2881 return(1);
2882 return(-1);
2883 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002884 if ((node1->type == XML_NAMESPACE_DECL) ||
2885 (node2->type == XML_NAMESPACE_DECL))
2886 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00002887 if (node1 == node2->prev)
2888 return(1);
2889 if (node1 == node2->next)
2890 return(-1);
2891
2892 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002893 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002894 */
2895 if ((node1->type == XML_ELEMENT_NODE) &&
2896 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002897 (0 > (long) node1->content) &&
2898 (0 > (long) node2->content) &&
2899 (node1->doc == node2->doc)) {
2900 long l1, l2;
2901
2902 l1 = -((long) node1->content);
2903 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002904 if (l1 < l2)
2905 return(1);
2906 if (l1 > l2)
2907 return(-1);
2908 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002909
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002910 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002911 * compute depth to root
2912 */
2913 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2914 if (cur == node1)
2915 return(1);
2916 depth2++;
2917 }
2918 root = cur;
2919 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2920 if (cur == node2)
2921 return(-1);
2922 depth1++;
2923 }
2924 /*
2925 * Distinct document (or distinct entities :-( ) case.
2926 */
2927 if (root != cur) {
2928 return(-2);
2929 }
2930 /*
2931 * get the nearest common ancestor.
2932 */
2933 while (depth1 > depth2) {
2934 depth1--;
2935 node1 = node1->parent;
2936 }
2937 while (depth2 > depth1) {
2938 depth2--;
2939 node2 = node2->parent;
2940 }
2941 while (node1->parent != node2->parent) {
2942 node1 = node1->parent;
2943 node2 = node2->parent;
2944 /* should not happen but just in case ... */
2945 if ((node1 == NULL) || (node2 == NULL))
2946 return(-2);
2947 }
2948 /*
2949 * Find who's first.
2950 */
Daniel Veillardf49be472004-02-17 11:48:18 +00002951 if (node1 == node2->prev)
2952 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00002953 if (node1 == node2->next)
2954 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00002955 /*
2956 * Speedup using document order if availble.
2957 */
2958 if ((node1->type == XML_ELEMENT_NODE) &&
2959 (node2->type == XML_ELEMENT_NODE) &&
2960 (0 > (long) node1->content) &&
2961 (0 > (long) node2->content) &&
2962 (node1->doc == node2->doc)) {
2963 long l1, l2;
2964
2965 l1 = -((long) node1->content);
2966 l2 = -((long) node2->content);
2967 if (l1 < l2)
2968 return(1);
2969 if (l1 > l2)
2970 return(-1);
2971 }
2972
Owen Taylor3473f882001-02-23 17:55:21 +00002973 for (cur = node1->next;cur != NULL;cur = cur->next)
2974 if (cur == node2)
2975 return(1);
2976 return(-1); /* assume there is no sibling list corruption */
2977}
2978
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00002979#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002980/**
2981 * xmlXPathCmpNodesExt:
2982 * @node1: the first node
2983 * @node2: the second node
2984 *
2985 * Compare two nodes w.r.t document order.
2986 * This one is optimized for handling of non-element nodes.
2987 *
2988 * Returns -2 in case of error 1 if first point < second point, 0 if
2989 * it's the same node, -1 otherwise
2990 */
2991static int
2992xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
2993 int depth1, depth2;
2994 int misc = 0, precedence1 = 0, precedence2 = 0;
2995 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
2996 xmlNodePtr cur, root;
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00002997 long l1, l2;
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002998
2999 if ((node1 == NULL) || (node2 == NULL))
3000 return(-2);
3001
3002 if (node1 == node2)
3003 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00003004
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003005 /*
3006 * a couple of optimizations which will avoid computations in most cases
Daniel Veillard45490ae2008-07-29 09:13:19 +00003007 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003008 switch (node1->type) {
3009 case XML_ELEMENT_NODE:
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003010 if (node2->type == XML_ELEMENT_NODE) {
3011 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
3012 (0 > (long) node2->content) &&
3013 (node1->doc == node2->doc))
Daniel Veillard45490ae2008-07-29 09:13:19 +00003014 {
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003015 l1 = -((long) node1->content);
3016 l2 = -((long) node2->content);
3017 if (l1 < l2)
3018 return(1);
3019 if (l1 > l2)
3020 return(-1);
3021 } else
Daniel Veillard45490ae2008-07-29 09:13:19 +00003022 goto turtle_comparison;
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003023 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003024 break;
3025 case XML_ATTRIBUTE_NODE:
3026 precedence1 = 1; /* element is owner */
3027 miscNode1 = node1;
3028 node1 = node1->parent;
3029 misc = 1;
3030 break;
3031 case XML_TEXT_NODE:
3032 case XML_CDATA_SECTION_NODE:
3033 case XML_COMMENT_NODE:
3034 case XML_PI_NODE: {
3035 miscNode1 = node1;
3036 /*
3037 * Find nearest element node.
Daniel Veillard45490ae2008-07-29 09:13:19 +00003038 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003039 if (node1->prev != NULL) {
3040 do {
3041 node1 = node1->prev;
3042 if (node1->type == XML_ELEMENT_NODE) {
3043 precedence1 = 3; /* element in prev-sibl axis */
3044 break;
3045 }
3046 if (node1->prev == NULL) {
3047 precedence1 = 2; /* element is parent */
3048 /*
3049 * URGENT TODO: Are there any cases, where the
3050 * parent of such a node is not an element node?
3051 */
3052 node1 = node1->parent;
3053 break;
3054 }
3055 } while (1);
3056 } else {
3057 precedence1 = 2; /* element is parent */
3058 node1 = node1->parent;
3059 }
William M. Brack31700e62007-06-13 20:33:02 +00003060 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
3061 (0 <= (long) node1->content)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003062 /*
3063 * Fallback for whatever case.
3064 */
3065 node1 = miscNode1;
3066 precedence1 = 0;
3067 } else
3068 misc = 1;
3069 }
3070 break;
3071 case XML_NAMESPACE_DECL:
3072 /*
3073 * TODO: why do we return 1 for namespace nodes?
3074 */
3075 return(1);
3076 default:
3077 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00003078 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003079 switch (node2->type) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00003080 case XML_ELEMENT_NODE:
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003081 break;
3082 case XML_ATTRIBUTE_NODE:
3083 precedence2 = 1; /* element is owner */
3084 miscNode2 = node2;
3085 node2 = node2->parent;
3086 misc = 1;
3087 break;
3088 case XML_TEXT_NODE:
3089 case XML_CDATA_SECTION_NODE:
3090 case XML_COMMENT_NODE:
3091 case XML_PI_NODE: {
3092 miscNode2 = node2;
3093 if (node2->prev != NULL) {
3094 do {
3095 node2 = node2->prev;
3096 if (node2->type == XML_ELEMENT_NODE) {
3097 precedence2 = 3; /* element in prev-sibl axis */
3098 break;
3099 }
3100 if (node2->prev == NULL) {
3101 precedence2 = 2; /* element is parent */
3102 node2 = node2->parent;
3103 break;
3104 }
3105 } while (1);
3106 } else {
3107 precedence2 = 2; /* element is parent */
3108 node2 = node2->parent;
Daniel Veillard45490ae2008-07-29 09:13:19 +00003109 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003110 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3111 (0 <= (long) node1->content))
3112 {
3113 node2 = miscNode2;
3114 precedence2 = 0;
3115 } else
3116 misc = 1;
3117 }
3118 break;
3119 case XML_NAMESPACE_DECL:
3120 return(1);
3121 default:
3122 break;
3123 }
3124 if (misc) {
3125 if (node1 == node2) {
3126 if (precedence1 == precedence2) {
3127 /*
3128 * The ugly case; but normally there aren't many
3129 * adjacent non-element nodes around.
3130 */
3131 cur = miscNode2->prev;
3132 while (cur != NULL) {
3133 if (cur == miscNode1)
3134 return(1);
3135 if (cur->type == XML_ELEMENT_NODE)
3136 return(-1);
3137 cur = cur->prev;
3138 }
3139 return (-1);
3140 } else {
3141 /*
3142 * Evaluate based on higher precedence wrt to the element.
3143 * TODO: This assumes attributes are sorted before content.
3144 * Is this 100% correct?
3145 */
3146 if (precedence1 < precedence2)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003147 return(1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003148 else
Daniel Veillard45490ae2008-07-29 09:13:19 +00003149 return(-1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003150 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00003151 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003152 /*
3153 * Special case: One of the helper-elements is contained by the other.
3154 * <foo>
3155 * <node2>
3156 * <node1>Text-1(precedence1 == 2)</node1>
3157 * </node2>
3158 * Text-6(precedence2 == 3)
3159 * </foo>
Daniel Veillard45490ae2008-07-29 09:13:19 +00003160 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003161 if ((precedence2 == 3) && (precedence1 > 1)) {
3162 cur = node1->parent;
3163 while (cur) {
3164 if (cur == node2)
3165 return(1);
3166 cur = cur->parent;
3167 }
3168 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00003169 if ((precedence1 == 3) && (precedence2 > 1)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003170 cur = node2->parent;
3171 while (cur) {
3172 if (cur == node1)
3173 return(-1);
3174 cur = cur->parent;
3175 }
3176 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00003177 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003178
3179 /*
3180 * Speedup using document order if availble.
3181 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00003182 if ((node1->type == XML_ELEMENT_NODE) &&
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003183 (node2->type == XML_ELEMENT_NODE) &&
3184 (0 > (long) node1->content) &&
3185 (0 > (long) node2->content) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +00003186 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003187
3188 l1 = -((long) node1->content);
3189 l2 = -((long) node2->content);
3190 if (l1 < l2)
3191 return(1);
3192 if (l1 > l2)
3193 return(-1);
3194 }
3195
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003196turtle_comparison:
3197
3198 if (node1 == node2->prev)
3199 return(1);
3200 if (node1 == node2->next)
3201 return(-1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003202 /*
3203 * compute depth to root
3204 */
3205 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3206 if (cur == node1)
3207 return(1);
3208 depth2++;
3209 }
3210 root = cur;
3211 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3212 if (cur == node2)
3213 return(-1);
3214 depth1++;
3215 }
3216 /*
3217 * Distinct document (or distinct entities :-( ) case.
3218 */
3219 if (root != cur) {
3220 return(-2);
3221 }
3222 /*
3223 * get the nearest common ancestor.
3224 */
3225 while (depth1 > depth2) {
3226 depth1--;
3227 node1 = node1->parent;
3228 }
3229 while (depth2 > depth1) {
3230 depth2--;
3231 node2 = node2->parent;
3232 }
3233 while (node1->parent != node2->parent) {
3234 node1 = node1->parent;
3235 node2 = node2->parent;
3236 /* should not happen but just in case ... */
3237 if ((node1 == NULL) || (node2 == NULL))
3238 return(-2);
3239 }
3240 /*
3241 * Find who's first.
3242 */
3243 if (node1 == node2->prev)
3244 return(1);
3245 if (node1 == node2->next)
3246 return(-1);
3247 /*
3248 * Speedup using document order if availble.
3249 */
3250 if ((node1->type == XML_ELEMENT_NODE) &&
3251 (node2->type == XML_ELEMENT_NODE) &&
3252 (0 > (long) node1->content) &&
3253 (0 > (long) node2->content) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +00003254 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003255
3256 l1 = -((long) node1->content);
3257 l2 = -((long) node2->content);
3258 if (l1 < l2)
3259 return(1);
3260 if (l1 > l2)
3261 return(-1);
3262 }
3263
3264 for (cur = node1->next;cur != NULL;cur = cur->next)
3265 if (cur == node2)
3266 return(1);
3267 return(-1); /* assume there is no sibling list corruption */
3268}
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003269#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003270
Owen Taylor3473f882001-02-23 17:55:21 +00003271/**
3272 * xmlXPathNodeSetSort:
3273 * @set: the node set
3274 *
3275 * Sort the node set in document order
3276 */
3277void
3278xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003279 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003280 xmlNodePtr tmp;
3281
3282 if (set == NULL)
3283 return;
3284
3285 /* Use Shell's sort to sort the node-set */
3286 len = set->nodeNr;
3287 for (incr = len / 2; incr > 0; incr /= 2) {
3288 for (i = incr; i < len; i++) {
3289 j = i - incr;
3290 while (j >= 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003291#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003292 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3293 set->nodeTab[j + incr]) == -1)
3294#else
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003295 if (xmlXPathCmpNodes(set->nodeTab[j],
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003296 set->nodeTab[j + incr]) == -1)
3297#endif
3298 {
Owen Taylor3473f882001-02-23 17:55:21 +00003299 tmp = set->nodeTab[j];
3300 set->nodeTab[j] = set->nodeTab[j + incr];
3301 set->nodeTab[j + incr] = tmp;
3302 j -= incr;
3303 } else
3304 break;
3305 }
3306 }
3307 }
3308}
3309
3310#define XML_NODESET_DEFAULT 10
3311/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003312 * xmlXPathNodeSetDupNs:
3313 * @node: the parent node of the namespace XPath node
3314 * @ns: the libxml namespace declaration node.
3315 *
3316 * Namespace node in libxml don't match the XPath semantic. In a node set
3317 * the namespace nodes are duplicated and the next pointer is set to the
3318 * parent node in the XPath semantic.
3319 *
3320 * Returns the newly created object.
3321 */
3322static xmlNodePtr
3323xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3324 xmlNsPtr cur;
3325
3326 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3327 return(NULL);
3328 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3329 return((xmlNodePtr) ns);
3330
3331 /*
3332 * Allocate a new Namespace and fill the fields.
3333 */
3334 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3335 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003336 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003337 return(NULL);
3338 }
3339 memset(cur, 0, sizeof(xmlNs));
3340 cur->type = XML_NAMESPACE_DECL;
3341 if (ns->href != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003342 cur->href = xmlStrdup(ns->href);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003343 if (ns->prefix != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003344 cur->prefix = xmlStrdup(ns->prefix);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003345 cur->next = (xmlNsPtr) node;
3346 return((xmlNodePtr) cur);
3347}
3348
3349/**
3350 * xmlXPathNodeSetFreeNs:
3351 * @ns: the XPath namespace node found in a nodeset.
3352 *
William M. Brack08171912003-12-29 02:52:11 +00003353 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003354 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00003355 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003356 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00003357void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003358xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3359 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3360 return;
3361
3362 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3363 if (ns->href != NULL)
3364 xmlFree((xmlChar *)ns->href);
3365 if (ns->prefix != NULL)
3366 xmlFree((xmlChar *)ns->prefix);
3367 xmlFree(ns);
3368 }
3369}
3370
3371/**
Owen Taylor3473f882001-02-23 17:55:21 +00003372 * xmlXPathNodeSetCreate:
3373 * @val: an initial xmlNodePtr, or NULL
3374 *
3375 * Create a new xmlNodeSetPtr of type double and of value @val
3376 *
3377 * Returns the newly created object.
3378 */
3379xmlNodeSetPtr
3380xmlXPathNodeSetCreate(xmlNodePtr val) {
3381 xmlNodeSetPtr ret;
3382
3383 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3384 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003385 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003386 return(NULL);
3387 }
3388 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3389 if (val != NULL) {
3390 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3391 sizeof(xmlNodePtr));
3392 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003393 xmlXPathErrMemory(NULL, "creating nodeset\n");
3394 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003395 return(NULL);
3396 }
3397 memset(ret->nodeTab, 0 ,
3398 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3399 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003400 if (val->type == XML_NAMESPACE_DECL) {
3401 xmlNsPtr ns = (xmlNsPtr) val;
3402
3403 ret->nodeTab[ret->nodeNr++] =
3404 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3405 } else
3406 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003407 }
3408 return(ret);
3409}
3410
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003411/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003412 * xmlXPathNodeSetCreateSize:
3413 * @size: the initial size of the set
3414 *
3415 * Create a new xmlNodeSetPtr of type double and of value @val
3416 *
3417 * Returns the newly created object.
3418 */
3419static xmlNodeSetPtr
3420xmlXPathNodeSetCreateSize(int size) {
3421 xmlNodeSetPtr ret;
3422
3423 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3424 if (ret == NULL) {
3425 xmlXPathErrMemory(NULL, "creating nodeset\n");
3426 return(NULL);
3427 }
3428 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3429 if (size < XML_NODESET_DEFAULT)
3430 size = XML_NODESET_DEFAULT;
3431 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3432 if (ret->nodeTab == NULL) {
3433 xmlXPathErrMemory(NULL, "creating nodeset\n");
3434 xmlFree(ret);
3435 return(NULL);
3436 }
3437 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
Daniel Veillard45490ae2008-07-29 09:13:19 +00003438 ret->nodeMax = size;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003439 return(ret);
3440}
3441
3442/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003443 * xmlXPathNodeSetContains:
3444 * @cur: the node-set
3445 * @val: the node
3446 *
3447 * checks whether @cur contains @val
3448 *
3449 * Returns true (1) if @cur contains @val, false (0) otherwise
3450 */
3451int
3452xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3453 int i;
3454
Daniel Veillarda82b1822004-11-08 16:24:57 +00003455 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003456 if (val->type == XML_NAMESPACE_DECL) {
3457 for (i = 0; i < cur->nodeNr; i++) {
3458 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3459 xmlNsPtr ns1, ns2;
3460
3461 ns1 = (xmlNsPtr) val;
3462 ns2 = (xmlNsPtr) cur->nodeTab[i];
3463 if (ns1 == ns2)
3464 return(1);
3465 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3466 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3467 return(1);
3468 }
3469 }
3470 } else {
3471 for (i = 0; i < cur->nodeNr; i++) {
3472 if (cur->nodeTab[i] == val)
3473 return(1);
3474 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003475 }
3476 return(0);
3477}
3478
3479/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003480 * xmlXPathNodeSetAddNs:
3481 * @cur: the initial node set
3482 * @node: the hosting node
3483 * @ns: a the namespace node
3484 *
3485 * add a new namespace node to an existing NodeSet
3486 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00003487void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003488xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3489 int i;
3490
Daniel Veillard45490ae2008-07-29 09:13:19 +00003491
Daniel Veillarda82b1822004-11-08 16:24:57 +00003492 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3493 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003494 (node->type != XML_ELEMENT_NODE))
3495 return;
3496
William M. Brack08171912003-12-29 02:52:11 +00003497 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003498 /*
William M. Brack08171912003-12-29 02:52:11 +00003499 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003500 */
3501 for (i = 0;i < cur->nodeNr;i++) {
3502 if ((cur->nodeTab[i] != NULL) &&
3503 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00003504 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003505 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3506 return;
3507 }
3508
3509 /*
3510 * grow the nodeTab if needed
3511 */
3512 if (cur->nodeMax == 0) {
3513 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3514 sizeof(xmlNodePtr));
3515 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003516 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003517 return;
3518 }
3519 memset(cur->nodeTab, 0 ,
3520 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3521 cur->nodeMax = XML_NODESET_DEFAULT;
3522 } else if (cur->nodeNr == cur->nodeMax) {
3523 xmlNodePtr *temp;
3524
Chris Evansd7958b22011-03-23 08:13:06 +08003525 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003526 sizeof(xmlNodePtr));
3527 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003528 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003529 return;
3530 }
Chris Evansd7958b22011-03-23 08:13:06 +08003531 cur->nodeMax *= 2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003532 cur->nodeTab = temp;
3533 }
3534 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3535}
3536
3537/**
Owen Taylor3473f882001-02-23 17:55:21 +00003538 * xmlXPathNodeSetAdd:
3539 * @cur: the initial node set
3540 * @val: a new xmlNodePtr
3541 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003542 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00003543 */
3544void
3545xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3546 int i;
3547
Daniel Veillarda82b1822004-11-08 16:24:57 +00003548 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003549
Daniel Veillardef0b4502003-03-24 13:57:34 +00003550#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00003551 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3552 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00003553#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00003554
William M. Brack08171912003-12-29 02:52:11 +00003555 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003556 /*
William M. Brack08171912003-12-29 02:52:11 +00003557 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00003558 */
3559 for (i = 0;i < cur->nodeNr;i++)
3560 if (cur->nodeTab[i] == val) return;
3561
3562 /*
3563 * grow the nodeTab if needed
3564 */
3565 if (cur->nodeMax == 0) {
3566 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3567 sizeof(xmlNodePtr));
3568 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003569 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003570 return;
3571 }
3572 memset(cur->nodeTab, 0 ,
3573 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3574 cur->nodeMax = XML_NODESET_DEFAULT;
3575 } else if (cur->nodeNr == cur->nodeMax) {
3576 xmlNodePtr *temp;
3577
Daniel Veillard0cbeb502010-11-15 12:06:29 +01003578 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003579 sizeof(xmlNodePtr));
3580 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003581 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003582 return;
3583 }
Daniel Veillard0cbeb502010-11-15 12:06:29 +01003584 cur->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003585 cur->nodeTab = temp;
3586 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003587 if (val->type == XML_NAMESPACE_DECL) {
3588 xmlNsPtr ns = (xmlNsPtr) val;
3589
Daniel Veillard45490ae2008-07-29 09:13:19 +00003590 cur->nodeTab[cur->nodeNr++] =
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003591 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3592 } else
3593 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003594}
3595
3596/**
3597 * xmlXPathNodeSetAddUnique:
3598 * @cur: the initial node set
3599 * @val: a new xmlNodePtr
3600 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003601 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00003602 * when we are sure the node is not already in the set.
3603 */
3604void
3605xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00003606 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003607
Daniel Veillardef0b4502003-03-24 13:57:34 +00003608#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00003609 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3610 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00003611#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00003612
William M. Brack08171912003-12-29 02:52:11 +00003613 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003614 /*
3615 * grow the nodeTab if needed
3616 */
3617 if (cur->nodeMax == 0) {
3618 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3619 sizeof(xmlNodePtr));
3620 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003621 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003622 return;
3623 }
3624 memset(cur->nodeTab, 0 ,
3625 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3626 cur->nodeMax = XML_NODESET_DEFAULT;
3627 } else if (cur->nodeNr == cur->nodeMax) {
3628 xmlNodePtr *temp;
3629
Chris Evansd7958b22011-03-23 08:13:06 +08003630 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003631 sizeof(xmlNodePtr));
3632 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003633 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003634 return;
3635 }
3636 cur->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08003637 cur->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003638 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003639 if (val->type == XML_NAMESPACE_DECL) {
3640 xmlNsPtr ns = (xmlNsPtr) val;
3641
Daniel Veillard45490ae2008-07-29 09:13:19 +00003642 cur->nodeTab[cur->nodeNr++] =
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003643 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3644 } else
3645 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003646}
3647
3648/**
3649 * xmlXPathNodeSetMerge:
3650 * @val1: the first NodeSet or NULL
3651 * @val2: the second NodeSet
3652 *
3653 * Merges two nodesets, all nodes from @val2 are added to @val1
3654 * if @val1 is NULL, a new set is created and copied from @val2
3655 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003656 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003657 */
3658xmlNodeSetPtr
3659xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003660 int i, j, initNr, skip;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003661 xmlNodePtr n1, n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003662
3663 if (val2 == NULL) return(val1);
3664 if (val1 == NULL) {
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003665 val1 = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00003666 if (val1 == NULL)
3667 return (NULL);
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003668#if 0
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003669 /*
3670 * TODO: The optimization won't work in every case, since
3671 * those nasty namespace nodes need to be added with
3672 * xmlXPathNodeSetDupNs() to the set; thus a pure
3673 * memcpy is not possible.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00003674 * If there was a flag on the nodesetval, indicating that
3675 * some temporary nodes are in, that would be helpfull.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003676 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00003677 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003678 * Optimization: Create an equally sized node-set
3679 * and memcpy the content.
3680 */
3681 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3682 if (val1 == NULL)
3683 return(NULL);
3684 if (val2->nodeNr != 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003685 if (val2->nodeNr == 1)
3686 *(val1->nodeTab) = *(val2->nodeTab);
3687 else {
3688 memcpy(val1->nodeTab, val2->nodeTab,
3689 val2->nodeNr * sizeof(xmlNodePtr));
3690 }
3691 val1->nodeNr = val2->nodeNr;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003692 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003693 return(val1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003694#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003695 }
3696
William M. Brack08171912003-12-29 02:52:11 +00003697 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003698 initNr = val1->nodeNr;
3699
3700 for (i = 0;i < val2->nodeNr;i++) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00003701 n2 = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00003702 /*
William M. Brack08171912003-12-29 02:52:11 +00003703 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003704 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003705 skip = 0;
3706 for (j = 0; j < initNr; j++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003707 n1 = val1->nodeTab[j];
3708 if (n1 == n2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003709 skip = 1;
3710 break;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003711 } else if ((n1->type == XML_NAMESPACE_DECL) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +00003712 (n2->type == XML_NAMESPACE_DECL)) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003713 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3714 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3715 ((xmlNsPtr) n2)->prefix)))
3716 {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003717 skip = 1;
3718 break;
3719 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003720 }
3721 }
3722 if (skip)
3723 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00003724
3725 /*
3726 * grow the nodeTab if needed
3727 */
3728 if (val1->nodeMax == 0) {
3729 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3730 sizeof(xmlNodePtr));
3731 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003732 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003733 return(NULL);
3734 }
3735 memset(val1->nodeTab, 0 ,
3736 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3737 val1->nodeMax = XML_NODESET_DEFAULT;
3738 } else if (val1->nodeNr == val1->nodeMax) {
3739 xmlNodePtr *temp;
3740
Chris Evansd7958b22011-03-23 08:13:06 +08003741 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003742 sizeof(xmlNodePtr));
3743 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003744 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003745 return(NULL);
3746 }
3747 val1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08003748 val1->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003749 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003750 if (n2->type == XML_NAMESPACE_DECL) {
3751 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003752
3753 val1->nodeTab[val1->nodeNr++] =
3754 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3755 } else
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003756 val1->nodeTab[val1->nodeNr++] = n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003757 }
3758
3759 return(val1);
3760}
3761
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003762#if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
Owen Taylor3473f882001-02-23 17:55:21 +00003763/**
Daniel Veillard75be0132002-03-13 10:03:35 +00003764 * xmlXPathNodeSetMergeUnique:
3765 * @val1: the first NodeSet or NULL
3766 * @val2: the second NodeSet
3767 *
3768 * Merges two nodesets, all nodes from @val2 are added to @val1
3769 * if @val1 is NULL, a new set is created and copied from @val2
3770 *
3771 * Returns @val1 once extended or NULL in case of error.
3772 */
3773static xmlNodeSetPtr
3774xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00003775 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00003776
3777 if (val2 == NULL) return(val1);
3778 if (val1 == NULL) {
3779 val1 = xmlXPathNodeSetCreate(NULL);
3780 }
Daniel Veillardf88d8492008-04-01 08:00:31 +00003781 if (val1 == NULL)
3782 return (NULL);
Daniel Veillard75be0132002-03-13 10:03:35 +00003783
William M. Brack08171912003-12-29 02:52:11 +00003784 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00003785
3786 for (i = 0;i < val2->nodeNr;i++) {
3787 /*
3788 * grow the nodeTab if needed
3789 */
3790 if (val1->nodeMax == 0) {
3791 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3792 sizeof(xmlNodePtr));
3793 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003794 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00003795 return(NULL);
3796 }
3797 memset(val1->nodeTab, 0 ,
3798 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3799 val1->nodeMax = XML_NODESET_DEFAULT;
3800 } else if (val1->nodeNr == val1->nodeMax) {
3801 xmlNodePtr *temp;
3802
3803 val1->nodeMax *= 2;
3804 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3805 sizeof(xmlNodePtr));
3806 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003807 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00003808 return(NULL);
3809 }
3810 val1->nodeTab = temp;
3811 }
3812 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3813 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
3814
3815 val1->nodeTab[val1->nodeNr++] =
3816 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3817 } else
3818 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
3819 }
3820
3821 return(val1);
3822}
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003823#endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3824
3825/**
3826 * xmlXPathNodeSetMergeAndClear:
3827 * @set1: the first NodeSet or NULL
3828 * @set2: the second NodeSet
3829 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3830 *
3831 * Merges two nodesets, all nodes from @set2 are added to @set1
3832 * if @set1 is NULL, a new set is created and copied from @set2.
3833 * Checks for duplicate nodes. Clears set2.
3834 *
3835 * Returns @set1 once extended or NULL in case of error.
3836 */
3837static xmlNodeSetPtr
3838xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3839 int hasNullEntries)
3840{
3841 if ((set1 == NULL) && (hasNullEntries == 0)) {
3842 /*
3843 * Note that doing a memcpy of the list, namespace nodes are
3844 * just assigned to set1, since set2 is cleared anyway.
3845 */
3846 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3847 if (set1 == NULL)
3848 return(NULL);
3849 if (set2->nodeNr != 0) {
3850 memcpy(set1->nodeTab, set2->nodeTab,
3851 set2->nodeNr * sizeof(xmlNodePtr));
3852 set1->nodeNr = set2->nodeNr;
3853 }
3854 } else {
3855 int i, j, initNbSet1;
3856 xmlNodePtr n1, n2;
3857
3858 if (set1 == NULL)
Daniel Veillardf88d8492008-04-01 08:00:31 +00003859 set1 = xmlXPathNodeSetCreate(NULL);
3860 if (set1 == NULL)
3861 return (NULL);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003862
Daniel Veillard45490ae2008-07-29 09:13:19 +00003863 initNbSet1 = set1->nodeNr;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003864 for (i = 0;i < set2->nodeNr;i++) {
3865 n2 = set2->nodeTab[i];
3866 /*
3867 * Skip NULLed entries.
3868 */
3869 if (n2 == NULL)
3870 continue;
3871 /*
3872 * Skip duplicates.
3873 */
3874 for (j = 0; j < initNbSet1; j++) {
3875 n1 = set1->nodeTab[j];
Daniel Veillard45490ae2008-07-29 09:13:19 +00003876 if (n1 == n2) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003877 goto skip_node;
3878 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3879 (n2->type == XML_NAMESPACE_DECL))
Daniel Veillard45490ae2008-07-29 09:13:19 +00003880 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003881 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3882 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3883 ((xmlNsPtr) n2)->prefix)))
3884 {
3885 /*
3886 * Free the namespace node.
3887 */
3888 set2->nodeTab[i] = NULL;
3889 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3890 goto skip_node;
3891 }
3892 }
3893 }
3894 /*
3895 * grow the nodeTab if needed
3896 */
3897 if (set1->nodeMax == 0) {
3898 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3899 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3900 if (set1->nodeTab == NULL) {
3901 xmlXPathErrMemory(NULL, "merging nodeset\n");
3902 return(NULL);
3903 }
3904 memset(set1->nodeTab, 0,
3905 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3906 set1->nodeMax = XML_NODESET_DEFAULT;
3907 } else if (set1->nodeNr >= set1->nodeMax) {
3908 xmlNodePtr *temp;
Daniel Veillard45490ae2008-07-29 09:13:19 +00003909
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003910 temp = (xmlNodePtr *) xmlRealloc(
Chris Evansd7958b22011-03-23 08:13:06 +08003911 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003912 if (temp == NULL) {
3913 xmlXPathErrMemory(NULL, "merging nodeset\n");
3914 return(NULL);
3915 }
3916 set1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08003917 set1->nodeMax *= 2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003918 }
3919 if (n2->type == XML_NAMESPACE_DECL) {
3920 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard45490ae2008-07-29 09:13:19 +00003921
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003922 set1->nodeTab[set1->nodeNr++] =
3923 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3924 } else
3925 set1->nodeTab[set1->nodeNr++] = n2;
3926skip_node:
3927 {}
3928 }
3929 }
3930 set2->nodeNr = 0;
3931 return(set1);
3932}
3933
3934/**
3935 * xmlXPathNodeSetMergeAndClearNoDupls:
3936 * @set1: the first NodeSet or NULL
3937 * @set2: the second NodeSet
3938 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3939 *
3940 * Merges two nodesets, all nodes from @set2 are added to @set1
3941 * if @set1 is NULL, a new set is created and copied from @set2.
3942 * Doesn't chack for duplicate nodes. Clears set2.
3943 *
3944 * Returns @set1 once extended or NULL in case of error.
3945 */
3946static xmlNodeSetPtr
3947xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3948 int hasNullEntries)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003949{
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003950 if (set2 == NULL)
3951 return(set1);
3952 if ((set1 == NULL) && (hasNullEntries == 0)) {
3953 /*
3954 * Note that doing a memcpy of the list, namespace nodes are
3955 * just assigned to set1, since set2 is cleared anyway.
3956 */
3957 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3958 if (set1 == NULL)
3959 return(NULL);
3960 if (set2->nodeNr != 0) {
3961 memcpy(set1->nodeTab, set2->nodeTab,
3962 set2->nodeNr * sizeof(xmlNodePtr));
3963 set1->nodeNr = set2->nodeNr;
3964 }
3965 } else {
3966 int i;
3967 xmlNodePtr n2;
3968
3969 if (set1 == NULL)
3970 set1 = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00003971 if (set1 == NULL)
3972 return (NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +00003973
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003974 for (i = 0;i < set2->nodeNr;i++) {
3975 n2 = set2->nodeTab[i];
3976 /*
3977 * Skip NULLed entries.
3978 */
3979 if (n2 == NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003980 continue;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003981 if (set1->nodeMax == 0) {
3982 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3983 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3984 if (set1->nodeTab == NULL) {
3985 xmlXPathErrMemory(NULL, "merging nodeset\n");
3986 return(NULL);
3987 }
3988 memset(set1->nodeTab, 0,
3989 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3990 set1->nodeMax = XML_NODESET_DEFAULT;
3991 } else if (set1->nodeNr >= set1->nodeMax) {
3992 xmlNodePtr *temp;
Daniel Veillard45490ae2008-07-29 09:13:19 +00003993
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003994 temp = (xmlNodePtr *) xmlRealloc(
Chris Evansd7958b22011-03-23 08:13:06 +08003995 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003996 if (temp == NULL) {
3997 xmlXPathErrMemory(NULL, "merging nodeset\n");
3998 return(NULL);
3999 }
4000 set1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08004001 set1->nodeMax *= 2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004002 }
4003 set1->nodeTab[set1->nodeNr++] = n2;
4004 }
4005 }
4006 set2->nodeNr = 0;
4007 return(set1);
4008}
Daniel Veillard75be0132002-03-13 10:03:35 +00004009
4010/**
Owen Taylor3473f882001-02-23 17:55:21 +00004011 * xmlXPathNodeSetDel:
4012 * @cur: the initial node set
4013 * @val: an xmlNodePtr
4014 *
4015 * Removes an xmlNodePtr from an existing NodeSet
4016 */
4017void
4018xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4019 int i;
4020
4021 if (cur == NULL) return;
4022 if (val == NULL) return;
4023
4024 /*
William M. Brack08171912003-12-29 02:52:11 +00004025 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00004026 */
4027 for (i = 0;i < cur->nodeNr;i++)
4028 if (cur->nodeTab[i] == val) break;
4029
William M. Brack08171912003-12-29 02:52:11 +00004030 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00004031#ifdef DEBUG
Daniel Veillard45490ae2008-07-29 09:13:19 +00004032 xmlGenericError(xmlGenericErrorContext,
Owen Taylor3473f882001-02-23 17:55:21 +00004033 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4034 val->name);
4035#endif
4036 return;
4037 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004038 if ((cur->nodeTab[i] != NULL) &&
4039 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4040 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004041 cur->nodeNr--;
4042 for (;i < cur->nodeNr;i++)
4043 cur->nodeTab[i] = cur->nodeTab[i + 1];
4044 cur->nodeTab[cur->nodeNr] = NULL;
4045}
4046
4047/**
4048 * xmlXPathNodeSetRemove:
4049 * @cur: the initial node set
4050 * @val: the index to remove
4051 *
4052 * Removes an entry from an existing NodeSet list.
4053 */
4054void
4055xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4056 if (cur == NULL) return;
4057 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004058 if ((cur->nodeTab[val] != NULL) &&
4059 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4060 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00004061 cur->nodeNr--;
4062 for (;val < cur->nodeNr;val++)
4063 cur->nodeTab[val] = cur->nodeTab[val + 1];
4064 cur->nodeTab[cur->nodeNr] = NULL;
4065}
4066
4067/**
4068 * xmlXPathFreeNodeSet:
4069 * @obj: the xmlNodeSetPtr to free
4070 *
4071 * Free the NodeSet compound (not the actual nodes !).
4072 */
4073void
4074xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4075 if (obj == NULL) return;
4076 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004077 int i;
4078
William M. Brack08171912003-12-29 02:52:11 +00004079 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004080 for (i = 0;i < obj->nodeNr;i++)
4081 if ((obj->nodeTab[i] != NULL) &&
4082 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4083 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004084 xmlFree(obj->nodeTab);
4085 }
Owen Taylor3473f882001-02-23 17:55:21 +00004086 xmlFree(obj);
4087}
4088
4089/**
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004090 * xmlXPathNodeSetClear:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004091 * @set: the node set to clear
Daniel Veillard45490ae2008-07-29 09:13:19 +00004092 *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004093 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4094 * are feed), but does *not* free the list itself. Sets the length of the
4095 * list to 0.
4096 */
4097static void
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004098xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4099{
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004100 if ((set == NULL) || (set->nodeNr <= 0))
4101 return;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004102 else if (hasNsNodes) {
4103 int i;
4104 xmlNodePtr node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004105
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004106 for (i = 0; i < set->nodeNr; i++) {
4107 node = set->nodeTab[i];
4108 if ((node != NULL) &&
4109 (node->type == XML_NAMESPACE_DECL))
4110 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004111 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004112 }
4113 set->nodeNr = 0;
4114}
4115
4116/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004117 * xmlXPathNodeSetClearFromPos:
4118 * @set: the node set to be cleared
4119 * @pos: the start position to clear from
Daniel Veillard45490ae2008-07-29 09:13:19 +00004120 *
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004121 * Clears the list from temporary XPath objects (e.g. namespace nodes
4122 * are feed) starting with the entry at @pos, but does *not* free the list
4123 * itself. Sets the length of the list to @pos.
4124 */
4125static void
4126xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4127{
4128 if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4129 return;
4130 else if ((hasNsNodes)) {
4131 int i;
4132 xmlNodePtr node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004133
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004134 for (i = pos; i < set->nodeNr; i++) {
4135 node = set->nodeTab[i];
4136 if ((node != NULL) &&
4137 (node->type == XML_NAMESPACE_DECL))
4138 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004139 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004140 }
4141 set->nodeNr = pos;
4142}
4143
4144/**
Owen Taylor3473f882001-02-23 17:55:21 +00004145 * xmlXPathFreeValueTree:
4146 * @obj: the xmlNodeSetPtr to free
4147 *
4148 * Free the NodeSet compound and the actual tree, this is different
4149 * from xmlXPathFreeNodeSet()
4150 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004151static void
Owen Taylor3473f882001-02-23 17:55:21 +00004152xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4153 int i;
4154
4155 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00004156
4157 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004158 for (i = 0;i < obj->nodeNr;i++) {
4159 if (obj->nodeTab[i] != NULL) {
4160 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4161 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4162 } else {
4163 xmlFreeNodeList(obj->nodeTab[i]);
4164 }
4165 }
4166 }
Owen Taylor3473f882001-02-23 17:55:21 +00004167 xmlFree(obj->nodeTab);
4168 }
Owen Taylor3473f882001-02-23 17:55:21 +00004169 xmlFree(obj);
4170}
4171
4172#if defined(DEBUG) || defined(DEBUG_STEP)
4173/**
4174 * xmlGenericErrorContextNodeSet:
4175 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00004176 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00004177 *
4178 * Quick display of a NodeSet
4179 */
4180void
4181xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4182 int i;
4183
4184 if (output == NULL) output = xmlGenericErrorContext;
4185 if (obj == NULL) {
4186 fprintf(output, "NodeSet == NULL !\n");
4187 return;
4188 }
4189 if (obj->nodeNr == 0) {
4190 fprintf(output, "NodeSet is empty\n");
4191 return;
4192 }
4193 if (obj->nodeTab == NULL) {
4194 fprintf(output, " nodeTab == NULL !\n");
4195 return;
4196 }
4197 for (i = 0; i < obj->nodeNr; i++) {
4198 if (obj->nodeTab[i] == NULL) {
4199 fprintf(output, " NULL !\n");
4200 return;
4201 }
4202 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4203 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4204 fprintf(output, " /");
4205 else if (obj->nodeTab[i]->name == NULL)
4206 fprintf(output, " noname!");
4207 else fprintf(output, " %s", obj->nodeTab[i]->name);
4208 }
4209 fprintf(output, "\n");
4210}
4211#endif
4212
4213/**
4214 * xmlXPathNewNodeSet:
4215 * @val: the NodePtr value
4216 *
4217 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4218 * it with the single Node @val
4219 *
4220 * Returns the newly created object.
4221 */
4222xmlXPathObjectPtr
4223xmlXPathNewNodeSet(xmlNodePtr val) {
4224 xmlXPathObjectPtr ret;
4225
4226 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4227 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004228 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004229 return(NULL);
4230 }
4231 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4232 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00004233 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004234 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00004235 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004236#ifdef XP_DEBUG_OBJ_USAGE
4237 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4238#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004239 return(ret);
4240}
4241
4242/**
4243 * xmlXPathNewValueTree:
4244 * @val: the NodePtr value
4245 *
4246 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4247 * it with the tree root @val
4248 *
4249 * Returns the newly created object.
4250 */
4251xmlXPathObjectPtr
4252xmlXPathNewValueTree(xmlNodePtr val) {
4253 xmlXPathObjectPtr ret;
4254
4255 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4256 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004257 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004258 return(NULL);
4259 }
4260 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4261 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00004262 ret->boolval = 1;
4263 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00004264 ret->nodesetval = xmlXPathNodeSetCreate(val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004265#ifdef XP_DEBUG_OBJ_USAGE
4266 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4267#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004268 return(ret);
4269}
4270
4271/**
4272 * xmlXPathNewNodeSetList:
4273 * @val: an existing NodeSet
4274 *
4275 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4276 * it with the Nodeset @val
4277 *
4278 * Returns the newly created object.
4279 */
4280xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004281xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4282{
Owen Taylor3473f882001-02-23 17:55:21 +00004283 xmlXPathObjectPtr ret;
4284 int i;
4285
4286 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004287 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00004288 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004289 ret = xmlXPathNewNodeSet(NULL);
4290 else {
4291 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004292 if (ret)
4293 for (i = 1; i < val->nodeNr; ++i)
4294 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004295 }
Owen Taylor3473f882001-02-23 17:55:21 +00004296
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004297 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004298}
4299
4300/**
4301 * xmlXPathWrapNodeSet:
4302 * @val: the NodePtr value
4303 *
4304 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4305 *
4306 * Returns the newly created object.
4307 */
4308xmlXPathObjectPtr
4309xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4310 xmlXPathObjectPtr ret;
4311
4312 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4313 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004314 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004315 return(NULL);
4316 }
4317 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4318 ret->type = XPATH_NODESET;
4319 ret->nodesetval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004320#ifdef XP_DEBUG_OBJ_USAGE
4321 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4322#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004323 return(ret);
4324}
4325
4326/**
4327 * xmlXPathFreeNodeSetList:
4328 * @obj: an existing NodeSetList object
4329 *
4330 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4331 * the list contrary to xmlXPathFreeObject().
4332 */
4333void
4334xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4335 if (obj == NULL) return;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004336#ifdef XP_DEBUG_OBJ_USAGE
4337 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4338#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004339 xmlFree(obj);
4340}
4341
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004342/**
4343 * xmlXPathDifference:
4344 * @nodes1: a node-set
4345 * @nodes2: a node-set
4346 *
4347 * Implements the EXSLT - Sets difference() function:
4348 * node-set set:difference (node-set, node-set)
4349 *
4350 * Returns the difference between the two node sets, or nodes1 if
4351 * nodes2 is empty
4352 */
4353xmlNodeSetPtr
4354xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4355 xmlNodeSetPtr ret;
4356 int i, l1;
4357 xmlNodePtr cur;
4358
4359 if (xmlXPathNodeSetIsEmpty(nodes2))
4360 return(nodes1);
4361
4362 ret = xmlXPathNodeSetCreate(NULL);
4363 if (xmlXPathNodeSetIsEmpty(nodes1))
4364 return(ret);
4365
4366 l1 = xmlXPathNodeSetGetLength(nodes1);
4367
4368 for (i = 0; i < l1; i++) {
4369 cur = xmlXPathNodeSetItem(nodes1, i);
4370 if (!xmlXPathNodeSetContains(nodes2, cur))
4371 xmlXPathNodeSetAddUnique(ret, cur);
4372 }
4373 return(ret);
4374}
4375
4376/**
4377 * xmlXPathIntersection:
4378 * @nodes1: a node-set
4379 * @nodes2: a node-set
4380 *
4381 * Implements the EXSLT - Sets intersection() function:
4382 * node-set set:intersection (node-set, node-set)
4383 *
4384 * Returns a node set comprising the nodes that are within both the
4385 * node sets passed as arguments
4386 */
4387xmlNodeSetPtr
4388xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4389 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4390 int i, l1;
4391 xmlNodePtr cur;
4392
Daniel Veillardf88d8492008-04-01 08:00:31 +00004393 if (ret == NULL)
4394 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004395 if (xmlXPathNodeSetIsEmpty(nodes1))
4396 return(ret);
4397 if (xmlXPathNodeSetIsEmpty(nodes2))
4398 return(ret);
4399
4400 l1 = xmlXPathNodeSetGetLength(nodes1);
4401
4402 for (i = 0; i < l1; i++) {
4403 cur = xmlXPathNodeSetItem(nodes1, i);
4404 if (xmlXPathNodeSetContains(nodes2, cur))
4405 xmlXPathNodeSetAddUnique(ret, cur);
4406 }
4407 return(ret);
4408}
4409
4410/**
4411 * xmlXPathDistinctSorted:
4412 * @nodes: a node-set, sorted by document order
4413 *
4414 * Implements the EXSLT - Sets distinct() function:
4415 * node-set set:distinct (node-set)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004416 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004417 * Returns a subset of the nodes contained in @nodes, or @nodes if
4418 * it is empty
4419 */
4420xmlNodeSetPtr
4421xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4422 xmlNodeSetPtr ret;
4423 xmlHashTablePtr hash;
4424 int i, l;
4425 xmlChar * strval;
4426 xmlNodePtr cur;
4427
4428 if (xmlXPathNodeSetIsEmpty(nodes))
4429 return(nodes);
4430
4431 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004432 if (ret == NULL)
4433 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004434 l = xmlXPathNodeSetGetLength(nodes);
4435 hash = xmlHashCreate (l);
4436 for (i = 0; i < l; i++) {
4437 cur = xmlXPathNodeSetItem(nodes, i);
4438 strval = xmlXPathCastNodeToString(cur);
4439 if (xmlHashLookup(hash, strval) == NULL) {
4440 xmlHashAddEntry(hash, strval, strval);
4441 xmlXPathNodeSetAddUnique(ret, cur);
4442 } else {
4443 xmlFree(strval);
4444 }
4445 }
4446 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4447 return(ret);
4448}
4449
4450/**
4451 * xmlXPathDistinct:
4452 * @nodes: a node-set
4453 *
4454 * Implements the EXSLT - Sets distinct() function:
4455 * node-set set:distinct (node-set)
4456 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4457 * is called with the sorted node-set
4458 *
4459 * Returns a subset of the nodes contained in @nodes, or @nodes if
4460 * it is empty
4461 */
4462xmlNodeSetPtr
4463xmlXPathDistinct (xmlNodeSetPtr nodes) {
4464 if (xmlXPathNodeSetIsEmpty(nodes))
4465 return(nodes);
4466
4467 xmlXPathNodeSetSort(nodes);
4468 return(xmlXPathDistinctSorted(nodes));
4469}
4470
4471/**
4472 * xmlXPathHasSameNodes:
4473 * @nodes1: a node-set
4474 * @nodes2: a node-set
4475 *
4476 * Implements the EXSLT - Sets has-same-nodes function:
4477 * boolean set:has-same-node(node-set, node-set)
4478 *
4479 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4480 * otherwise
4481 */
4482int
4483xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4484 int i, l;
4485 xmlNodePtr cur;
4486
4487 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4488 xmlXPathNodeSetIsEmpty(nodes2))
4489 return(0);
4490
4491 l = xmlXPathNodeSetGetLength(nodes1);
4492 for (i = 0; i < l; i++) {
4493 cur = xmlXPathNodeSetItem(nodes1, i);
4494 if (xmlXPathNodeSetContains(nodes2, cur))
4495 return(1);
4496 }
4497 return(0);
4498}
4499
4500/**
4501 * xmlXPathNodeLeadingSorted:
4502 * @nodes: a node-set, sorted by document order
4503 * @node: a node
4504 *
4505 * Implements the EXSLT - Sets leading() function:
4506 * node-set set:leading (node-set, node-set)
4507 *
4508 * Returns the nodes in @nodes that precede @node in document order,
4509 * @nodes if @node is NULL or an empty node-set if @nodes
4510 * doesn't contain @node
4511 */
4512xmlNodeSetPtr
4513xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4514 int i, l;
4515 xmlNodePtr cur;
4516 xmlNodeSetPtr ret;
4517
4518 if (node == NULL)
4519 return(nodes);
4520
4521 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004522 if (ret == NULL)
4523 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004524 if (xmlXPathNodeSetIsEmpty(nodes) ||
4525 (!xmlXPathNodeSetContains(nodes, node)))
4526 return(ret);
4527
4528 l = xmlXPathNodeSetGetLength(nodes);
4529 for (i = 0; i < l; i++) {
4530 cur = xmlXPathNodeSetItem(nodes, i);
4531 if (cur == node)
4532 break;
4533 xmlXPathNodeSetAddUnique(ret, cur);
4534 }
4535 return(ret);
4536}
4537
4538/**
4539 * xmlXPathNodeLeading:
4540 * @nodes: a node-set
4541 * @node: a node
4542 *
4543 * Implements the EXSLT - Sets leading() function:
4544 * node-set set:leading (node-set, node-set)
4545 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4546 * is called.
4547 *
4548 * Returns the nodes in @nodes that precede @node in document order,
4549 * @nodes if @node is NULL or an empty node-set if @nodes
4550 * doesn't contain @node
4551 */
4552xmlNodeSetPtr
4553xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4554 xmlXPathNodeSetSort(nodes);
4555 return(xmlXPathNodeLeadingSorted(nodes, node));
4556}
4557
4558/**
4559 * xmlXPathLeadingSorted:
4560 * @nodes1: a node-set, sorted by document order
4561 * @nodes2: a node-set, sorted by document order
4562 *
4563 * Implements the EXSLT - Sets leading() function:
4564 * node-set set:leading (node-set, node-set)
4565 *
4566 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4567 * in document order, @nodes1 if @nodes2 is NULL or empty or
4568 * an empty node-set if @nodes1 doesn't contain @nodes2
4569 */
4570xmlNodeSetPtr
4571xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4572 if (xmlXPathNodeSetIsEmpty(nodes2))
4573 return(nodes1);
4574 return(xmlXPathNodeLeadingSorted(nodes1,
4575 xmlXPathNodeSetItem(nodes2, 1)));
4576}
4577
4578/**
4579 * xmlXPathLeading:
4580 * @nodes1: a node-set
4581 * @nodes2: a node-set
4582 *
4583 * Implements the EXSLT - Sets leading() function:
4584 * node-set set:leading (node-set, node-set)
4585 * @nodes1 and @nodes2 are sorted by document order, then
4586 * #exslSetsLeadingSorted is called.
4587 *
4588 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4589 * in document order, @nodes1 if @nodes2 is NULL or empty or
4590 * an empty node-set if @nodes1 doesn't contain @nodes2
4591 */
4592xmlNodeSetPtr
4593xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4594 if (xmlXPathNodeSetIsEmpty(nodes2))
4595 return(nodes1);
4596 if (xmlXPathNodeSetIsEmpty(nodes1))
4597 return(xmlXPathNodeSetCreate(NULL));
4598 xmlXPathNodeSetSort(nodes1);
4599 xmlXPathNodeSetSort(nodes2);
4600 return(xmlXPathNodeLeadingSorted(nodes1,
4601 xmlXPathNodeSetItem(nodes2, 1)));
4602}
4603
4604/**
4605 * xmlXPathNodeTrailingSorted:
4606 * @nodes: a node-set, sorted by document order
4607 * @node: a node
4608 *
4609 * Implements the EXSLT - Sets trailing() function:
4610 * node-set set:trailing (node-set, node-set)
4611 *
4612 * Returns the nodes in @nodes that follow @node in document order,
4613 * @nodes if @node is NULL or an empty node-set if @nodes
4614 * doesn't contain @node
4615 */
4616xmlNodeSetPtr
4617xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4618 int i, l;
4619 xmlNodePtr cur;
4620 xmlNodeSetPtr ret;
4621
4622 if (node == NULL)
4623 return(nodes);
4624
4625 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004626 if (ret == NULL)
4627 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004628 if (xmlXPathNodeSetIsEmpty(nodes) ||
4629 (!xmlXPathNodeSetContains(nodes, node)))
4630 return(ret);
4631
4632 l = xmlXPathNodeSetGetLength(nodes);
William M. Brack97ac8192007-06-06 17:19:24 +00004633 for (i = l - 1; i >= 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004634 cur = xmlXPathNodeSetItem(nodes, i);
4635 if (cur == node)
4636 break;
4637 xmlXPathNodeSetAddUnique(ret, cur);
4638 }
William M. Brack97ac8192007-06-06 17:19:24 +00004639 xmlXPathNodeSetSort(ret); /* bug 413451 */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004640 return(ret);
4641}
4642
4643/**
4644 * xmlXPathNodeTrailing:
4645 * @nodes: a node-set
4646 * @node: a node
4647 *
4648 * Implements the EXSLT - Sets trailing() function:
4649 * node-set set:trailing (node-set, node-set)
4650 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4651 * is called.
4652 *
4653 * Returns the nodes in @nodes that follow @node in document order,
4654 * @nodes if @node is NULL or an empty node-set if @nodes
4655 * doesn't contain @node
4656 */
4657xmlNodeSetPtr
4658xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4659 xmlXPathNodeSetSort(nodes);
4660 return(xmlXPathNodeTrailingSorted(nodes, node));
4661}
4662
4663/**
4664 * xmlXPathTrailingSorted:
4665 * @nodes1: a node-set, sorted by document order
4666 * @nodes2: a node-set, sorted by document order
4667 *
4668 * Implements the EXSLT - Sets trailing() function:
4669 * node-set set:trailing (node-set, node-set)
4670 *
4671 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4672 * in document order, @nodes1 if @nodes2 is NULL or empty or
4673 * an empty node-set if @nodes1 doesn't contain @nodes2
4674 */
4675xmlNodeSetPtr
4676xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4677 if (xmlXPathNodeSetIsEmpty(nodes2))
4678 return(nodes1);
4679 return(xmlXPathNodeTrailingSorted(nodes1,
4680 xmlXPathNodeSetItem(nodes2, 0)));
4681}
4682
4683/**
4684 * xmlXPathTrailing:
4685 * @nodes1: a node-set
4686 * @nodes2: a node-set
4687 *
4688 * Implements the EXSLT - Sets trailing() function:
4689 * node-set set:trailing (node-set, node-set)
4690 * @nodes1 and @nodes2 are sorted by document order, then
4691 * #xmlXPathTrailingSorted is called.
4692 *
4693 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4694 * in document order, @nodes1 if @nodes2 is NULL or empty or
4695 * an empty node-set if @nodes1 doesn't contain @nodes2
4696 */
4697xmlNodeSetPtr
4698xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4699 if (xmlXPathNodeSetIsEmpty(nodes2))
4700 return(nodes1);
4701 if (xmlXPathNodeSetIsEmpty(nodes1))
4702 return(xmlXPathNodeSetCreate(NULL));
4703 xmlXPathNodeSetSort(nodes1);
4704 xmlXPathNodeSetSort(nodes2);
4705 return(xmlXPathNodeTrailingSorted(nodes1,
4706 xmlXPathNodeSetItem(nodes2, 0)));
4707}
4708
Owen Taylor3473f882001-02-23 17:55:21 +00004709/************************************************************************
4710 * *
4711 * Routines to handle extra functions *
4712 * *
4713 ************************************************************************/
4714
4715/**
4716 * xmlXPathRegisterFunc:
4717 * @ctxt: the XPath context
4718 * @name: the function name
4719 * @f: the function implementation or NULL
4720 *
4721 * Register a new function. If @f is NULL it unregisters the function
4722 *
4723 * Returns 0 in case of success, -1 in case of error
4724 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00004725int
Owen Taylor3473f882001-02-23 17:55:21 +00004726xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4727 xmlXPathFunction f) {
4728 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4729}
4730
4731/**
4732 * xmlXPathRegisterFuncNS:
4733 * @ctxt: the XPath context
4734 * @name: the function name
4735 * @ns_uri: the function namespace URI
4736 * @f: the function implementation or NULL
4737 *
4738 * Register a new function. If @f is NULL it unregisters the function
4739 *
4740 * Returns 0 in case of success, -1 in case of error
4741 */
4742int
4743xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4744 const xmlChar *ns_uri, xmlXPathFunction f) {
4745 if (ctxt == NULL)
4746 return(-1);
4747 if (name == NULL)
4748 return(-1);
4749
4750 if (ctxt->funcHash == NULL)
4751 ctxt->funcHash = xmlHashCreate(0);
4752 if (ctxt->funcHash == NULL)
4753 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004754 if (f == NULL)
4755 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
William M. Brackad0e67c2004-12-01 14:35:10 +00004756 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
Owen Taylor3473f882001-02-23 17:55:21 +00004757}
4758
4759/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00004760 * xmlXPathRegisterFuncLookup:
4761 * @ctxt: the XPath context
4762 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004763 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00004764 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004765 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00004766 */
4767void
4768xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4769 xmlXPathFuncLookupFunc f,
4770 void *funcCtxt) {
4771 if (ctxt == NULL)
4772 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004773 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004774 ctxt->funcLookupData = funcCtxt;
4775}
4776
4777/**
Owen Taylor3473f882001-02-23 17:55:21 +00004778 * xmlXPathFunctionLookup:
4779 * @ctxt: the XPath context
4780 * @name: the function name
4781 *
4782 * Search in the Function array of the context for the given
4783 * function.
4784 *
4785 * Returns the xmlXPathFunction or NULL if not found
4786 */
4787xmlXPathFunction
4788xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00004789 if (ctxt == NULL)
4790 return (NULL);
4791
4792 if (ctxt->funcLookupFunc != NULL) {
4793 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004794 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004795
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004796 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004797 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004798 if (ret != NULL)
4799 return(ret);
4800 }
Owen Taylor3473f882001-02-23 17:55:21 +00004801 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4802}
4803
4804/**
4805 * xmlXPathFunctionLookupNS:
4806 * @ctxt: the XPath context
4807 * @name: the function name
4808 * @ns_uri: the function namespace URI
4809 *
4810 * Search in the Function array of the context for the given
4811 * function.
4812 *
4813 * Returns the xmlXPathFunction or NULL if not found
4814 */
4815xmlXPathFunction
4816xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4817 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00004818 xmlXPathFunction ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004819
Owen Taylor3473f882001-02-23 17:55:21 +00004820 if (ctxt == NULL)
4821 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004822 if (name == NULL)
4823 return(NULL);
4824
Thomas Broyerba4ad322001-07-26 16:55:21 +00004825 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004826 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004827
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004828 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004829 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004830 if (ret != NULL)
4831 return(ret);
4832 }
4833
4834 if (ctxt->funcHash == NULL)
4835 return(NULL);
4836
William M. Brackad0e67c2004-12-01 14:35:10 +00004837 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4838 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004839}
4840
4841/**
4842 * xmlXPathRegisteredFuncsCleanup:
4843 * @ctxt: the XPath context
4844 *
4845 * Cleanup the XPath context data associated to registered functions
4846 */
4847void
4848xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4849 if (ctxt == NULL)
4850 return;
4851
4852 xmlHashFree(ctxt->funcHash, NULL);
4853 ctxt->funcHash = NULL;
4854}
4855
4856/************************************************************************
4857 * *
William M. Brack08171912003-12-29 02:52:11 +00004858 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00004859 * *
4860 ************************************************************************/
4861
4862/**
4863 * xmlXPathRegisterVariable:
4864 * @ctxt: the XPath context
4865 * @name: the variable name
4866 * @value: the variable value or NULL
4867 *
4868 * Register a new variable value. If @value is NULL it unregisters
4869 * the variable
4870 *
4871 * Returns 0 in case of success, -1 in case of error
4872 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00004873int
Owen Taylor3473f882001-02-23 17:55:21 +00004874xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4875 xmlXPathObjectPtr value) {
4876 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4877}
4878
4879/**
4880 * xmlXPathRegisterVariableNS:
4881 * @ctxt: the XPath context
4882 * @name: the variable name
4883 * @ns_uri: the variable namespace URI
4884 * @value: the variable value or NULL
4885 *
4886 * Register a new variable value. If @value is NULL it unregisters
4887 * the variable
4888 *
4889 * Returns 0 in case of success, -1 in case of error
4890 */
4891int
4892xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4893 const xmlChar *ns_uri,
4894 xmlXPathObjectPtr value) {
4895 if (ctxt == NULL)
4896 return(-1);
4897 if (name == NULL)
4898 return(-1);
4899
4900 if (ctxt->varHash == NULL)
4901 ctxt->varHash = xmlHashCreate(0);
4902 if (ctxt->varHash == NULL)
4903 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004904 if (value == NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004905 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
Daniel Veillard94394cd2003-10-29 17:07:51 +00004906 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00004907 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4908 (void *) value,
4909 (xmlHashDeallocator)xmlXPathFreeObject));
4910}
4911
4912/**
4913 * xmlXPathRegisterVariableLookup:
4914 * @ctxt: the XPath context
4915 * @f: the lookup function
4916 * @data: the lookup data
4917 *
4918 * register an external mechanism to do variable lookup
4919 */
4920void
4921xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4922 xmlXPathVariableLookupFunc f, void *data) {
4923 if (ctxt == NULL)
4924 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004925 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00004926 ctxt->varLookupData = data;
4927}
4928
4929/**
4930 * xmlXPathVariableLookup:
4931 * @ctxt: the XPath context
4932 * @name: the variable name
4933 *
4934 * Search in the Variable array of the context for the given
4935 * variable value.
4936 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00004937 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00004938 */
4939xmlXPathObjectPtr
4940xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4941 if (ctxt == NULL)
4942 return(NULL);
4943
4944 if (ctxt->varLookupFunc != NULL) {
4945 xmlXPathObjectPtr ret;
4946
4947 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4948 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00004949 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004950 }
4951 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4952}
4953
4954/**
4955 * xmlXPathVariableLookupNS:
4956 * @ctxt: the XPath context
4957 * @name: the variable name
4958 * @ns_uri: the variable namespace URI
4959 *
4960 * Search in the Variable array of the context for the given
Daniel Veillard45490ae2008-07-29 09:13:19 +00004961 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00004962 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00004963 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00004964 */
4965xmlXPathObjectPtr
4966xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4967 const xmlChar *ns_uri) {
4968 if (ctxt == NULL)
4969 return(NULL);
4970
4971 if (ctxt->varLookupFunc != NULL) {
4972 xmlXPathObjectPtr ret;
4973
4974 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4975 (ctxt->varLookupData, name, ns_uri);
4976 if (ret != NULL) return(ret);
4977 }
4978
4979 if (ctxt->varHash == NULL)
4980 return(NULL);
4981 if (name == NULL)
4982 return(NULL);
4983
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004984 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
Daniel Veillard8c357d52001-07-03 23:43:33 +00004985 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00004986}
4987
4988/**
4989 * xmlXPathRegisteredVariablesCleanup:
4990 * @ctxt: the XPath context
4991 *
4992 * Cleanup the XPath context data associated to registered variables
4993 */
4994void
4995xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4996 if (ctxt == NULL)
4997 return;
4998
Daniel Veillard76d66f42001-05-16 21:05:17 +00004999 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00005000 ctxt->varHash = NULL;
5001}
5002
5003/**
5004 * xmlXPathRegisterNs:
5005 * @ctxt: the XPath context
Daniel Veillarddb3ce962009-03-25 09:43:49 +00005006 * @prefix: the namespace prefix cannot be NULL or empty string
Owen Taylor3473f882001-02-23 17:55:21 +00005007 * @ns_uri: the namespace name
5008 *
5009 * Register a new namespace. If @ns_uri is NULL it unregisters
5010 * the namespace
5011 *
5012 * Returns 0 in case of success, -1 in case of error
5013 */
5014int
5015xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5016 const xmlChar *ns_uri) {
5017 if (ctxt == NULL)
5018 return(-1);
5019 if (prefix == NULL)
5020 return(-1);
Daniel Veillarddb3ce962009-03-25 09:43:49 +00005021 if (prefix[0] == 0)
5022 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00005023
5024 if (ctxt->nsHash == NULL)
5025 ctxt->nsHash = xmlHashCreate(10);
5026 if (ctxt->nsHash == NULL)
5027 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00005028 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00005029 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00005030 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00005031 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00005032 (xmlHashDeallocator)xmlFree));
5033}
5034
5035/**
5036 * xmlXPathNsLookup:
5037 * @ctxt: the XPath context
5038 * @prefix: the namespace prefix value
5039 *
5040 * Search in the namespace declaration array of the context for the given
5041 * namespace name associated to the given prefix
5042 *
5043 * Returns the value or NULL if not found
5044 */
5045const xmlChar *
5046xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5047 if (ctxt == NULL)
5048 return(NULL);
5049 if (prefix == NULL)
5050 return(NULL);
5051
5052#ifdef XML_XML_NAMESPACE
5053 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5054 return(XML_XML_NAMESPACE);
5055#endif
5056
Daniel Veillardc8f620b2001-04-30 20:31:33 +00005057 if (ctxt->namespaces != NULL) {
5058 int i;
5059
5060 for (i = 0;i < ctxt->nsNr;i++) {
5061 if ((ctxt->namespaces[i] != NULL) &&
5062 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5063 return(ctxt->namespaces[i]->href);
5064 }
5065 }
Owen Taylor3473f882001-02-23 17:55:21 +00005066
5067 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5068}
5069
5070/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005071 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00005072 * @ctxt: the XPath context
5073 *
5074 * Cleanup the XPath context data associated to registered variables
5075 */
5076void
5077xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5078 if (ctxt == NULL)
5079 return;
5080
Daniel Veillard42766c02002-08-22 20:52:17 +00005081 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00005082 ctxt->nsHash = NULL;
5083}
5084
5085/************************************************************************
5086 * *
5087 * Routines to handle Values *
5088 * *
5089 ************************************************************************/
5090
William M. Brack08171912003-12-29 02:52:11 +00005091/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005092
5093/**
5094 * xmlXPathNewFloat:
5095 * @val: the double value
5096 *
5097 * Create a new xmlXPathObjectPtr of type double and of value @val
5098 *
5099 * Returns the newly created object.
5100 */
5101xmlXPathObjectPtr
5102xmlXPathNewFloat(double val) {
5103 xmlXPathObjectPtr ret;
5104
5105 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5106 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005107 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005108 return(NULL);
5109 }
5110 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5111 ret->type = XPATH_NUMBER;
5112 ret->floatval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005113#ifdef XP_DEBUG_OBJ_USAGE
5114 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5115#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005116 return(ret);
5117}
5118
5119/**
5120 * xmlXPathNewBoolean:
5121 * @val: the boolean value
5122 *
5123 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5124 *
5125 * Returns the newly created object.
5126 */
5127xmlXPathObjectPtr
5128xmlXPathNewBoolean(int val) {
5129 xmlXPathObjectPtr ret;
5130
5131 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5132 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005133 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005134 return(NULL);
5135 }
5136 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5137 ret->type = XPATH_BOOLEAN;
5138 ret->boolval = (val != 0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005139#ifdef XP_DEBUG_OBJ_USAGE
5140 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5141#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005142 return(ret);
5143}
5144
5145/**
5146 * xmlXPathNewString:
5147 * @val: the xmlChar * value
5148 *
5149 * Create a new xmlXPathObjectPtr of type string and of value @val
5150 *
5151 * Returns the newly created object.
5152 */
5153xmlXPathObjectPtr
5154xmlXPathNewString(const xmlChar *val) {
5155 xmlXPathObjectPtr ret;
5156
5157 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5158 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005159 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005160 return(NULL);
5161 }
5162 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5163 ret->type = XPATH_STRING;
5164 if (val != NULL)
5165 ret->stringval = xmlStrdup(val);
5166 else
5167 ret->stringval = xmlStrdup((const xmlChar *)"");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005168#ifdef XP_DEBUG_OBJ_USAGE
5169 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5170#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005171 return(ret);
5172}
5173
5174/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005175 * xmlXPathWrapString:
5176 * @val: the xmlChar * value
5177 *
5178 * Wraps the @val string into an XPath object.
5179 *
5180 * Returns the newly created object.
5181 */
5182xmlXPathObjectPtr
5183xmlXPathWrapString (xmlChar *val) {
5184 xmlXPathObjectPtr ret;
5185
5186 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5187 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005188 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005189 return(NULL);
5190 }
5191 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5192 ret->type = XPATH_STRING;
5193 ret->stringval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005194#ifdef XP_DEBUG_OBJ_USAGE
5195 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5196#endif
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005197 return(ret);
5198}
5199
5200/**
Owen Taylor3473f882001-02-23 17:55:21 +00005201 * xmlXPathNewCString:
5202 * @val: the char * value
5203 *
5204 * Create a new xmlXPathObjectPtr of type string and of value @val
5205 *
5206 * Returns the newly created object.
5207 */
5208xmlXPathObjectPtr
5209xmlXPathNewCString(const char *val) {
5210 xmlXPathObjectPtr ret;
5211
5212 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5213 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005214 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005215 return(NULL);
5216 }
5217 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5218 ret->type = XPATH_STRING;
5219 ret->stringval = xmlStrdup(BAD_CAST val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005220#ifdef XP_DEBUG_OBJ_USAGE
5221 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5222#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005223 return(ret);
5224}
5225
5226/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005227 * xmlXPathWrapCString:
5228 * @val: the char * value
5229 *
5230 * Wraps a string into an XPath object.
5231 *
5232 * Returns the newly created object.
5233 */
5234xmlXPathObjectPtr
5235xmlXPathWrapCString (char * val) {
5236 return(xmlXPathWrapString((xmlChar *)(val)));
5237}
5238
5239/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005240 * xmlXPathWrapExternal:
5241 * @val: the user data
5242 *
5243 * Wraps the @val data into an XPath object.
5244 *
5245 * Returns the newly created object.
5246 */
5247xmlXPathObjectPtr
5248xmlXPathWrapExternal (void *val) {
5249 xmlXPathObjectPtr ret;
5250
5251 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5252 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005253 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005254 return(NULL);
5255 }
5256 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5257 ret->type = XPATH_USERS;
5258 ret->user = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005259#ifdef XP_DEBUG_OBJ_USAGE
5260 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5261#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005262 return(ret);
5263}
5264
5265/**
Owen Taylor3473f882001-02-23 17:55:21 +00005266 * xmlXPathObjectCopy:
5267 * @val: the original object
5268 *
5269 * allocate a new copy of a given object
5270 *
5271 * Returns the newly created object.
5272 */
5273xmlXPathObjectPtr
5274xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5275 xmlXPathObjectPtr ret;
5276
5277 if (val == NULL)
5278 return(NULL);
5279
5280 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5281 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005282 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005283 return(NULL);
5284 }
5285 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005286#ifdef XP_DEBUG_OBJ_USAGE
5287 xmlXPathDebugObjUsageRequested(NULL, val->type);
5288#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005289 switch (val->type) {
5290 case XPATH_BOOLEAN:
5291 case XPATH_NUMBER:
5292 case XPATH_POINT:
5293 case XPATH_RANGE:
5294 break;
5295 case XPATH_STRING:
5296 ret->stringval = xmlStrdup(val->stringval);
5297 break;
5298 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00005299#if 0
5300/*
5301 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5302 this previous handling is no longer correct, and can cause some serious
5303 problems (ref. bug 145547)
5304*/
Owen Taylor3473f882001-02-23 17:55:21 +00005305 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005306 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005307 xmlNodePtr cur, tmp;
5308 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005309
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005310 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005311 top = xmlNewDoc(NULL);
5312 top->name = (char *)
5313 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005314 ret->user = top;
5315 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005316 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005317 cur = val->nodesetval->nodeTab[0]->children;
5318 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005319 tmp = xmlDocCopyNode(cur, top, 1);
5320 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005321 cur = cur->next;
5322 }
5323 }
William M. Bracke9449c52004-07-11 14:41:20 +00005324
Daniel Veillard9adc0462003-03-24 18:39:54 +00005325 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005326 } else
Owen Taylor3473f882001-02-23 17:55:21 +00005327 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005328 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00005329 break;
William M. Bracke9449c52004-07-11 14:41:20 +00005330#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005331 case XPATH_NODESET:
5332 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005333 /* Do not deallocate the copied tree value */
5334 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005335 break;
5336 case XPATH_LOCATIONSET:
5337#ifdef LIBXML_XPTR_ENABLED
5338 {
5339 xmlLocationSetPtr loc = val->user;
5340 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5341 break;
5342 }
5343#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00005344 case XPATH_USERS:
5345 ret->user = val->user;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005346 break;
Thomas Broyer47334c02001-10-07 16:41:52 +00005347 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00005348 xmlGenericError(xmlGenericErrorContext,
5349 "xmlXPathObjectCopy: unsupported type %d\n",
5350 val->type);
5351 break;
5352 }
5353 return(ret);
5354}
5355
5356/**
5357 * xmlXPathFreeObject:
5358 * @obj: the object to free
5359 *
5360 * Free up an xmlXPathObjectPtr object.
5361 */
5362void
5363xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5364 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005365 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00005366 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00005367#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005368 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005369 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00005370 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00005371 } else
5372#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005373 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
William M. Bracke9449c52004-07-11 14:41:20 +00005374 if (obj->nodesetval != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00005375 xmlXPathFreeValueTree(obj->nodesetval);
Daniel Veillard77851712001-02-27 21:54:07 +00005376 } else {
5377 if (obj->nodesetval != NULL)
5378 xmlXPathFreeNodeSet(obj->nodesetval);
5379 }
Owen Taylor3473f882001-02-23 17:55:21 +00005380#ifdef LIBXML_XPTR_ENABLED
5381 } else if (obj->type == XPATH_LOCATIONSET) {
5382 if (obj->user != NULL)
5383 xmlXPtrFreeLocationSet(obj->user);
5384#endif
5385 } else if (obj->type == XPATH_STRING) {
5386 if (obj->stringval != NULL)
5387 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005388 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005389#ifdef XP_DEBUG_OBJ_USAGE
5390 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5391#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00005392 xmlFree(obj);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005393}
Owen Taylor3473f882001-02-23 17:55:21 +00005394
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005395/**
5396 * xmlXPathReleaseObject:
5397 * @obj: the xmlXPathObjectPtr to free or to cache
5398 *
5399 * Depending on the state of the cache this frees the given
5400 * XPath object or stores it in the cache.
5401 */
5402static void
5403xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5404{
5405#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5406 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5407 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5408
5409#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5410
5411 if (obj == NULL)
5412 return;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005413 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005414 xmlXPathFreeObject(obj);
Daniel Veillard45490ae2008-07-29 09:13:19 +00005415 } else {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005416 xmlXPathContextCachePtr cache =
5417 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005418
5419 switch (obj->type) {
5420 case XPATH_NODESET:
5421 case XPATH_XSLT_TREE:
5422 if (obj->nodesetval != NULL) {
5423 if (obj->boolval) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00005424 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005425 * It looks like the @boolval is used for
5426 * evaluation if this an XSLT Result Tree Fragment.
5427 * TODO: Check if this assumption is correct.
5428 */
5429 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5430 xmlXPathFreeValueTree(obj->nodesetval);
5431 obj->nodesetval = NULL;
5432 } else if ((obj->nodesetval->nodeMax <= 40) &&
5433 (XP_CACHE_WANTS(cache->nodesetObjs,
5434 cache->maxNodeset)))
5435 {
5436 XP_CACHE_ADD(cache->nodesetObjs, obj);
5437 goto obj_cached;
5438 } else {
5439 xmlXPathFreeNodeSet(obj->nodesetval);
5440 obj->nodesetval = NULL;
5441 }
5442 }
5443 break;
5444 case XPATH_STRING:
5445 if (obj->stringval != NULL)
5446 xmlFree(obj->stringval);
5447
5448 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5449 XP_CACHE_ADD(cache->stringObjs, obj);
5450 goto obj_cached;
5451 }
5452 break;
5453 case XPATH_BOOLEAN:
5454 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5455 XP_CACHE_ADD(cache->booleanObjs, obj);
5456 goto obj_cached;
5457 }
5458 break;
5459 case XPATH_NUMBER:
5460 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5461 XP_CACHE_ADD(cache->numberObjs, obj);
5462 goto obj_cached;
5463 }
5464 break;
5465#ifdef LIBXML_XPTR_ENABLED
5466 case XPATH_LOCATIONSET:
5467 if (obj->user != NULL) {
5468 xmlXPtrFreeLocationSet(obj->user);
5469 }
5470 goto free_obj;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005471#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005472 default:
5473 goto free_obj;
5474 }
5475
5476 /*
5477 * Fallback to adding to the misc-objects slot.
5478 */
5479 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5480 XP_CACHE_ADD(cache->miscObjs, obj);
5481 } else
5482 goto free_obj;
5483
5484obj_cached:
5485
5486#ifdef XP_DEBUG_OBJ_USAGE
5487 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5488#endif
5489
5490 if (obj->nodesetval != NULL) {
5491 xmlNodeSetPtr tmpset = obj->nodesetval;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005492
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005493 /*
5494 * TODO: Due to those nasty ns-nodes, we need to traverse
5495 * the list and free the ns-nodes.
5496 * URGENT TODO: Check if it's actually slowing things down.
5497 * Maybe we shouldn't try to preserve the list.
5498 */
5499 if (tmpset->nodeNr > 1) {
5500 int i;
5501 xmlNodePtr node;
5502
5503 for (i = 0; i < tmpset->nodeNr; i++) {
5504 node = tmpset->nodeTab[i];
5505 if ((node != NULL) &&
5506 (node->type == XML_NAMESPACE_DECL))
5507 {
5508 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5509 }
5510 }
5511 } else if (tmpset->nodeNr == 1) {
5512 if ((tmpset->nodeTab[0] != NULL) &&
5513 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5514 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
Daniel Veillard45490ae2008-07-29 09:13:19 +00005515 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005516 tmpset->nodeNr = 0;
5517 memset(obj, 0, sizeof(xmlXPathObject));
5518 obj->nodesetval = tmpset;
5519 } else
5520 memset(obj, 0, sizeof(xmlXPathObject));
5521
5522 return;
5523
5524free_obj:
5525 /*
5526 * Cache is full; free the object.
Daniel Veillard45490ae2008-07-29 09:13:19 +00005527 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005528 if (obj->nodesetval != NULL)
5529 xmlXPathFreeNodeSet(obj->nodesetval);
5530#ifdef XP_DEBUG_OBJ_USAGE
5531 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5532#endif
5533 xmlFree(obj);
5534 }
5535 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005536}
5537
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005538
5539/************************************************************************
5540 * *
5541 * Type Casting Routines *
5542 * *
5543 ************************************************************************/
5544
5545/**
5546 * xmlXPathCastBooleanToString:
5547 * @val: a boolean
5548 *
5549 * Converts a boolean to its string value.
5550 *
5551 * Returns a newly allocated string.
5552 */
5553xmlChar *
5554xmlXPathCastBooleanToString (int val) {
5555 xmlChar *ret;
5556 if (val)
5557 ret = xmlStrdup((const xmlChar *) "true");
5558 else
5559 ret = xmlStrdup((const xmlChar *) "false");
5560 return(ret);
5561}
5562
5563/**
5564 * xmlXPathCastNumberToString:
5565 * @val: a number
5566 *
5567 * Converts a number to its string value.
5568 *
5569 * Returns a newly allocated string.
5570 */
5571xmlChar *
5572xmlXPathCastNumberToString (double val) {
5573 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00005574 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005575 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005576 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005577 break;
5578 case -1:
5579 ret = xmlStrdup((const xmlChar *) "-Infinity");
5580 break;
5581 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00005582 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005583 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005584 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5585 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005586 } else {
5587 /* could be improved */
5588 char buf[100];
Daniel Veillard11ce4002006-03-10 00:36:23 +00005589 xmlXPathFormatNumber(val, buf, 99);
5590 buf[99] = 0;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005591 ret = xmlStrdup((const xmlChar *) buf);
5592 }
5593 }
5594 return(ret);
5595}
5596
5597/**
5598 * xmlXPathCastNodeToString:
5599 * @node: a node
5600 *
5601 * Converts a node to its string value.
5602 *
5603 * Returns a newly allocated string.
5604 */
5605xmlChar *
5606xmlXPathCastNodeToString (xmlNodePtr node) {
William M. Brackd611c882007-05-31 05:07:17 +00005607xmlChar *ret;
5608 if ((ret = xmlNodeGetContent(node)) == NULL)
5609 ret = xmlStrdup((const xmlChar *) "");
5610 return(ret);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005611}
5612
5613/**
5614 * xmlXPathCastNodeSetToString:
5615 * @ns: a node-set
5616 *
5617 * Converts a node-set to its string value.
5618 *
5619 * Returns a newly allocated string.
5620 */
5621xmlChar *
5622xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5623 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5624 return(xmlStrdup((const xmlChar *) ""));
5625
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00005626 if (ns->nodeNr > 1)
5627 xmlXPathNodeSetSort(ns);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005628 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5629}
5630
5631/**
5632 * xmlXPathCastToString:
5633 * @val: an XPath object
5634 *
5635 * Converts an existing object to its string() equivalent
5636 *
Kasimier T. Buchcik50128ad2006-08-15 13:04:07 +00005637 * Returns the allocated string value of the object, NULL in case of error.
Daniel Veillard45490ae2008-07-29 09:13:19 +00005638 * It's up to the caller to free the string memory with xmlFree().
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005639 */
5640xmlChar *
5641xmlXPathCastToString(xmlXPathObjectPtr val) {
5642 xmlChar *ret = NULL;
5643
5644 if (val == NULL)
5645 return(xmlStrdup((const xmlChar *) ""));
5646 switch (val->type) {
5647 case XPATH_UNDEFINED:
5648#ifdef DEBUG_EXPR
5649 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5650#endif
5651 ret = xmlStrdup((const xmlChar *) "");
5652 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005653 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005654 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005655 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5656 break;
5657 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00005658 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005659 case XPATH_BOOLEAN:
5660 ret = xmlXPathCastBooleanToString(val->boolval);
5661 break;
5662 case XPATH_NUMBER: {
5663 ret = xmlXPathCastNumberToString(val->floatval);
5664 break;
5665 }
5666 case XPATH_USERS:
5667 case XPATH_POINT:
5668 case XPATH_RANGE:
5669 case XPATH_LOCATIONSET:
5670 TODO
5671 ret = xmlStrdup((const xmlChar *) "");
5672 break;
5673 }
5674 return(ret);
5675}
5676
5677/**
5678 * xmlXPathConvertString:
5679 * @val: an XPath object
5680 *
5681 * Converts an existing object to its string() equivalent
5682 *
5683 * Returns the new object, the old one is freed (or the operation
5684 * is done directly on @val)
5685 */
5686xmlXPathObjectPtr
5687xmlXPathConvertString(xmlXPathObjectPtr val) {
5688 xmlChar *res = NULL;
5689
5690 if (val == NULL)
5691 return(xmlXPathNewCString(""));
5692
5693 switch (val->type) {
5694 case XPATH_UNDEFINED:
5695#ifdef DEBUG_EXPR
5696 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5697#endif
5698 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005699 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005700 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005701 res = xmlXPathCastNodeSetToString(val->nodesetval);
5702 break;
5703 case XPATH_STRING:
5704 return(val);
5705 case XPATH_BOOLEAN:
5706 res = xmlXPathCastBooleanToString(val->boolval);
5707 break;
5708 case XPATH_NUMBER:
5709 res = xmlXPathCastNumberToString(val->floatval);
5710 break;
5711 case XPATH_USERS:
5712 case XPATH_POINT:
5713 case XPATH_RANGE:
5714 case XPATH_LOCATIONSET:
5715 TODO;
5716 break;
5717 }
5718 xmlXPathFreeObject(val);
5719 if (res == NULL)
5720 return(xmlXPathNewCString(""));
5721 return(xmlXPathWrapString(res));
5722}
5723
5724/**
5725 * xmlXPathCastBooleanToNumber:
5726 * @val: a boolean
5727 *
5728 * Converts a boolean to its number value
5729 *
5730 * Returns the number value
5731 */
5732double
5733xmlXPathCastBooleanToNumber(int val) {
5734 if (val)
5735 return(1.0);
5736 return(0.0);
5737}
5738
5739/**
5740 * xmlXPathCastStringToNumber:
5741 * @val: a string
5742 *
5743 * Converts a string to its number value
5744 *
5745 * Returns the number value
5746 */
5747double
5748xmlXPathCastStringToNumber(const xmlChar * val) {
5749 return(xmlXPathStringEvalNumber(val));
5750}
5751
5752/**
5753 * xmlXPathCastNodeToNumber:
5754 * @node: a node
5755 *
5756 * Converts a node to its number value
5757 *
5758 * Returns the number value
5759 */
5760double
5761xmlXPathCastNodeToNumber (xmlNodePtr node) {
5762 xmlChar *strval;
5763 double ret;
5764
5765 if (node == NULL)
5766 return(xmlXPathNAN);
5767 strval = xmlXPathCastNodeToString(node);
5768 if (strval == NULL)
5769 return(xmlXPathNAN);
5770 ret = xmlXPathCastStringToNumber(strval);
5771 xmlFree(strval);
5772
5773 return(ret);
5774}
5775
5776/**
5777 * xmlXPathCastNodeSetToNumber:
5778 * @ns: a node-set
5779 *
5780 * Converts a node-set to its number value
5781 *
5782 * Returns the number value
5783 */
5784double
5785xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5786 xmlChar *str;
5787 double ret;
5788
5789 if (ns == NULL)
5790 return(xmlXPathNAN);
5791 str = xmlXPathCastNodeSetToString(ns);
5792 ret = xmlXPathCastStringToNumber(str);
5793 xmlFree(str);
5794 return(ret);
5795}
5796
5797/**
5798 * xmlXPathCastToNumber:
5799 * @val: an XPath object
5800 *
5801 * Converts an XPath object to its number value
5802 *
5803 * Returns the number value
5804 */
5805double
5806xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5807 double ret = 0.0;
5808
5809 if (val == NULL)
5810 return(xmlXPathNAN);
5811 switch (val->type) {
5812 case XPATH_UNDEFINED:
5813#ifdef DEGUB_EXPR
5814 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5815#endif
5816 ret = xmlXPathNAN;
5817 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005818 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005819 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005820 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5821 break;
5822 case XPATH_STRING:
5823 ret = xmlXPathCastStringToNumber(val->stringval);
5824 break;
5825 case XPATH_NUMBER:
5826 ret = val->floatval;
5827 break;
5828 case XPATH_BOOLEAN:
5829 ret = xmlXPathCastBooleanToNumber(val->boolval);
5830 break;
5831 case XPATH_USERS:
5832 case XPATH_POINT:
5833 case XPATH_RANGE:
5834 case XPATH_LOCATIONSET:
5835 TODO;
5836 ret = xmlXPathNAN;
5837 break;
5838 }
5839 return(ret);
5840}
5841
5842/**
5843 * xmlXPathConvertNumber:
5844 * @val: an XPath object
5845 *
5846 * Converts an existing object to its number() equivalent
5847 *
5848 * Returns the new object, the old one is freed (or the operation
5849 * is done directly on @val)
5850 */
5851xmlXPathObjectPtr
5852xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5853 xmlXPathObjectPtr ret;
5854
5855 if (val == NULL)
5856 return(xmlXPathNewFloat(0.0));
5857 if (val->type == XPATH_NUMBER)
5858 return(val);
5859 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5860 xmlXPathFreeObject(val);
5861 return(ret);
5862}
5863
5864/**
5865 * xmlXPathCastNumberToBoolean:
5866 * @val: a number
5867 *
5868 * Converts a number to its boolean value
5869 *
5870 * Returns the boolean value
5871 */
5872int
5873xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00005874 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005875 return(0);
5876 return(1);
5877}
5878
5879/**
5880 * xmlXPathCastStringToBoolean:
5881 * @val: a string
5882 *
5883 * Converts a string to its boolean value
5884 *
5885 * Returns the boolean value
5886 */
5887int
5888xmlXPathCastStringToBoolean (const xmlChar *val) {
5889 if ((val == NULL) || (xmlStrlen(val) == 0))
5890 return(0);
5891 return(1);
5892}
5893
5894/**
5895 * xmlXPathCastNodeSetToBoolean:
5896 * @ns: a node-set
5897 *
5898 * Converts a node-set to its boolean value
5899 *
5900 * Returns the boolean value
5901 */
5902int
5903xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5904 if ((ns == NULL) || (ns->nodeNr == 0))
5905 return(0);
5906 return(1);
5907}
5908
5909/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005910 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005911 * @val: an XPath object
5912 *
5913 * Converts an XPath object to its boolean value
5914 *
5915 * Returns the boolean value
5916 */
5917int
5918xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5919 int ret = 0;
5920
5921 if (val == NULL)
5922 return(0);
5923 switch (val->type) {
5924 case XPATH_UNDEFINED:
5925#ifdef DEBUG_EXPR
5926 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
5927#endif
5928 ret = 0;
5929 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005930 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005931 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005932 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5933 break;
5934 case XPATH_STRING:
5935 ret = xmlXPathCastStringToBoolean(val->stringval);
5936 break;
5937 case XPATH_NUMBER:
5938 ret = xmlXPathCastNumberToBoolean(val->floatval);
5939 break;
5940 case XPATH_BOOLEAN:
5941 ret = val->boolval;
5942 break;
5943 case XPATH_USERS:
5944 case XPATH_POINT:
5945 case XPATH_RANGE:
5946 case XPATH_LOCATIONSET:
5947 TODO;
5948 ret = 0;
5949 break;
5950 }
5951 return(ret);
5952}
5953
5954
5955/**
5956 * xmlXPathConvertBoolean:
5957 * @val: an XPath object
5958 *
5959 * Converts an existing object to its boolean() equivalent
5960 *
5961 * Returns the new object, the old one is freed (or the operation
5962 * is done directly on @val)
5963 */
5964xmlXPathObjectPtr
5965xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
5966 xmlXPathObjectPtr ret;
5967
5968 if (val == NULL)
5969 return(xmlXPathNewBoolean(0));
5970 if (val->type == XPATH_BOOLEAN)
5971 return(val);
5972 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
5973 xmlXPathFreeObject(val);
5974 return(ret);
5975}
5976
Owen Taylor3473f882001-02-23 17:55:21 +00005977/************************************************************************
5978 * *
5979 * Routines to handle XPath contexts *
5980 * *
5981 ************************************************************************/
5982
5983/**
5984 * xmlXPathNewContext:
5985 * @doc: the XML document
5986 *
5987 * Create a new xmlXPathContext
5988 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00005989 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00005990 */
5991xmlXPathContextPtr
5992xmlXPathNewContext(xmlDocPtr doc) {
5993 xmlXPathContextPtr ret;
5994
5995 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
5996 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005997 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005998 return(NULL);
5999 }
6000 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6001 ret->doc = doc;
6002 ret->node = NULL;
6003
6004 ret->varHash = NULL;
6005
6006 ret->nb_types = 0;
6007 ret->max_types = 0;
6008 ret->types = NULL;
6009
6010 ret->funcHash = xmlHashCreate(0);
6011
6012 ret->nb_axis = 0;
6013 ret->max_axis = 0;
6014 ret->axis = NULL;
6015
6016 ret->nsHash = NULL;
6017 ret->user = NULL;
6018
6019 ret->contextSize = -1;
6020 ret->proximityPosition = -1;
6021
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006022#ifdef XP_DEFAULT_CACHE_ON
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006023 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006024 xmlXPathFreeContext(ret);
6025 return(NULL);
6026 }
6027#endif
6028
Daniel Veillard45490ae2008-07-29 09:13:19 +00006029 xmlXPathRegisterAllFunctions(ret);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006030
Owen Taylor3473f882001-02-23 17:55:21 +00006031 return(ret);
6032}
6033
6034/**
6035 * xmlXPathFreeContext:
6036 * @ctxt: the context to free
6037 *
6038 * Free up an xmlXPathContext
6039 */
6040void
6041xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006042 if (ctxt == NULL) return;
6043
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006044 if (ctxt->cache != NULL)
6045 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
Owen Taylor3473f882001-02-23 17:55:21 +00006046 xmlXPathRegisteredNsCleanup(ctxt);
6047 xmlXPathRegisteredFuncsCleanup(ctxt);
6048 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006049 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00006050 xmlFree(ctxt);
6051}
6052
6053/************************************************************************
6054 * *
6055 * Routines to handle XPath parser contexts *
6056 * *
6057 ************************************************************************/
6058
6059#define CHECK_CTXT(ctxt) \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006060 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00006061 __xmlRaiseError(NULL, NULL, NULL, \
6062 NULL, NULL, XML_FROM_XPATH, \
6063 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6064 __FILE__, __LINE__, \
6065 NULL, NULL, NULL, 0, 0, \
6066 "NULL context pointer\n"); \
6067 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00006068 } \
6069
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006070#define CHECK_CTXT_NEG(ctxt) \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006071 if (ctxt == NULL) { \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006072 __xmlRaiseError(NULL, NULL, NULL, \
6073 NULL, NULL, XML_FROM_XPATH, \
6074 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6075 __FILE__, __LINE__, \
6076 NULL, NULL, NULL, 0, 0, \
6077 "NULL context pointer\n"); \
6078 return(-1); \
6079 } \
6080
Owen Taylor3473f882001-02-23 17:55:21 +00006081
6082#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00006083 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006084 (ctxt->doc->children == NULL)) { \
Daniel Veillard57b25162004-11-06 14:50:18 +00006085 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00006086 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00006087 }
Owen Taylor3473f882001-02-23 17:55:21 +00006088
6089
6090/**
6091 * xmlXPathNewParserContext:
6092 * @str: the XPath expression
6093 * @ctxt: the XPath context
6094 *
6095 * Create a new xmlXPathParserContext
6096 *
6097 * Returns the xmlXPathParserContext just allocated.
6098 */
6099xmlXPathParserContextPtr
6100xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6101 xmlXPathParserContextPtr ret;
6102
6103 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6104 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006105 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006106 return(NULL);
6107 }
6108 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6109 ret->cur = ret->base = str;
6110 ret->context = ctxt;
6111
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006112 ret->comp = xmlXPathNewCompExpr();
6113 if (ret->comp == NULL) {
6114 xmlFree(ret->valueTab);
6115 xmlFree(ret);
6116 return(NULL);
6117 }
Daniel Veillard4773df22004-01-23 13:15:13 +00006118 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6119 ret->comp->dict = ctxt->dict;
6120 xmlDictReference(ret->comp->dict);
6121 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006122
6123 return(ret);
6124}
6125
6126/**
6127 * xmlXPathCompParserContext:
6128 * @comp: the XPath compiled expression
6129 * @ctxt: the XPath context
6130 *
6131 * Create a new xmlXPathParserContext when processing a compiled expression
6132 *
6133 * Returns the xmlXPathParserContext just allocated.
6134 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006135static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006136xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6137 xmlXPathParserContextPtr ret;
6138
6139 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6140 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006141 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006142 return(NULL);
6143 }
6144 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6145
Owen Taylor3473f882001-02-23 17:55:21 +00006146 /* Allocate the value stack */
Daniel Veillard45490ae2008-07-29 09:13:19 +00006147 ret->valueTab = (xmlXPathObjectPtr *)
Owen Taylor3473f882001-02-23 17:55:21 +00006148 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006149 if (ret->valueTab == NULL) {
6150 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006151 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006152 return(NULL);
6153 }
Owen Taylor3473f882001-02-23 17:55:21 +00006154 ret->valueNr = 0;
6155 ret->valueMax = 10;
6156 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006157
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006158 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006159 ret->comp = comp;
6160
Owen Taylor3473f882001-02-23 17:55:21 +00006161 return(ret);
6162}
6163
6164/**
6165 * xmlXPathFreeParserContext:
6166 * @ctxt: the context to free
6167 *
6168 * Free up an xmlXPathParserContext
6169 */
6170void
6171xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6172 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006173 xmlFree(ctxt->valueTab);
6174 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00006175 if (ctxt->comp != NULL) {
6176#ifdef XPATH_STREAMING
6177 if (ctxt->comp->stream != NULL) {
6178 xmlFreePatternList(ctxt->comp->stream);
6179 ctxt->comp->stream = NULL;
6180 }
6181#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006182 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard56de87e2005-02-16 00:22:29 +00006183 }
Owen Taylor3473f882001-02-23 17:55:21 +00006184 xmlFree(ctxt);
6185}
6186
6187/************************************************************************
6188 * *
6189 * The implicit core function library *
6190 * *
6191 ************************************************************************/
6192
Owen Taylor3473f882001-02-23 17:55:21 +00006193/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006194 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00006195 * @node: a node pointer
6196 *
6197 * Function computing the beginning of the string value of the node,
6198 * used to speed up comparisons
6199 *
6200 * Returns an int usable as a hash
6201 */
6202static unsigned int
6203xmlXPathNodeValHash(xmlNodePtr node) {
6204 int len = 2;
6205 const xmlChar * string = NULL;
6206 xmlNodePtr tmp = NULL;
6207 unsigned int ret = 0;
6208
6209 if (node == NULL)
6210 return(0);
6211
Daniel Veillard9adc0462003-03-24 18:39:54 +00006212 if (node->type == XML_DOCUMENT_NODE) {
6213 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6214 if (tmp == NULL)
6215 node = node->children;
6216 else
6217 node = tmp;
6218
6219 if (node == NULL)
6220 return(0);
6221 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006222
6223 switch (node->type) {
6224 case XML_COMMENT_NODE:
6225 case XML_PI_NODE:
6226 case XML_CDATA_SECTION_NODE:
6227 case XML_TEXT_NODE:
6228 string = node->content;
6229 if (string == NULL)
6230 return(0);
6231 if (string[0] == 0)
6232 return(0);
6233 return(((unsigned int) string[0]) +
6234 (((unsigned int) string[1]) << 8));
6235 case XML_NAMESPACE_DECL:
6236 string = ((xmlNsPtr)node)->href;
6237 if (string == NULL)
6238 return(0);
6239 if (string[0] == 0)
6240 return(0);
6241 return(((unsigned int) string[0]) +
6242 (((unsigned int) string[1]) << 8));
6243 case XML_ATTRIBUTE_NODE:
6244 tmp = ((xmlAttrPtr) node)->children;
6245 break;
6246 case XML_ELEMENT_NODE:
6247 tmp = node->children;
6248 break;
6249 default:
6250 return(0);
6251 }
6252 while (tmp != NULL) {
6253 switch (tmp->type) {
6254 case XML_COMMENT_NODE:
6255 case XML_PI_NODE:
6256 case XML_CDATA_SECTION_NODE:
6257 case XML_TEXT_NODE:
6258 string = tmp->content;
6259 break;
6260 case XML_NAMESPACE_DECL:
6261 string = ((xmlNsPtr)tmp)->href;
6262 break;
6263 default:
6264 break;
6265 }
6266 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006267 if (len == 1) {
6268 return(ret + (((unsigned int) string[0]) << 8));
6269 }
6270 if (string[1] == 0) {
6271 len = 1;
6272 ret = (unsigned int) string[0];
6273 } else {
6274 return(((unsigned int) string[0]) +
6275 (((unsigned int) string[1]) << 8));
6276 }
6277 }
6278 /*
6279 * Skip to next node
6280 */
6281 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6282 if (tmp->children->type != XML_ENTITY_DECL) {
6283 tmp = tmp->children;
6284 continue;
6285 }
6286 }
6287 if (tmp == node)
6288 break;
6289
6290 if (tmp->next != NULL) {
6291 tmp = tmp->next;
6292 continue;
6293 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00006294
Daniel Veillardf06307e2001-07-03 10:35:50 +00006295 do {
6296 tmp = tmp->parent;
6297 if (tmp == NULL)
6298 break;
6299 if (tmp == node) {
6300 tmp = NULL;
6301 break;
6302 }
6303 if (tmp->next != NULL) {
6304 tmp = tmp->next;
6305 break;
6306 }
6307 } while (tmp != NULL);
6308 }
6309 return(ret);
6310}
6311
6312/**
6313 * xmlXPathStringHash:
6314 * @string: a string
6315 *
6316 * Function computing the beginning of the string value of the node,
6317 * used to speed up comparisons
6318 *
6319 * Returns an int usable as a hash
6320 */
6321static unsigned int
6322xmlXPathStringHash(const xmlChar * string) {
6323 if (string == NULL)
6324 return((unsigned int) 0);
6325 if (string[0] == 0)
6326 return(0);
6327 return(((unsigned int) string[0]) +
6328 (((unsigned int) string[1]) << 8));
6329}
6330
6331/**
Owen Taylor3473f882001-02-23 17:55:21 +00006332 * xmlXPathCompareNodeSetFloat:
6333 * @ctxt: the XPath Parser context
6334 * @inf: less than (1) or greater than (0)
6335 * @strict: is the comparison strict
6336 * @arg: the node set
6337 * @f: the value
6338 *
6339 * Implement the compare operation between a nodeset and a number
6340 * @ns < @val (1, 1, ...
6341 * @ns <= @val (1, 0, ...
6342 * @ns > @val (0, 1, ...
6343 * @ns >= @val (0, 0, ...
6344 *
6345 * If one object to be compared is a node-set and the other is a number,
6346 * then the comparison will be true if and only if there is a node in the
6347 * node-set such that the result of performing the comparison on the number
6348 * to be compared and on the result of converting the string-value of that
6349 * node to a number using the number function is true.
6350 *
6351 * Returns 0 or 1 depending on the results of the test.
6352 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006353static int
Owen Taylor3473f882001-02-23 17:55:21 +00006354xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6355 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6356 int i, ret = 0;
6357 xmlNodeSetPtr ns;
6358 xmlChar *str2;
6359
6360 if ((f == NULL) || (arg == NULL) ||
6361 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006362 xmlXPathReleaseObject(ctxt->context, arg);
6363 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006364 return(0);
6365 }
6366 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006367 if (ns != NULL) {
6368 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006369 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006370 if (str2 != NULL) {
6371 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006372 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006373 xmlFree(str2);
6374 xmlXPathNumberFunction(ctxt, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006375 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006376 ret = xmlXPathCompareValues(ctxt, inf, strict);
6377 if (ret)
6378 break;
6379 }
6380 }
Owen Taylor3473f882001-02-23 17:55:21 +00006381 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006382 xmlXPathReleaseObject(ctxt->context, arg);
6383 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006384 return(ret);
6385}
6386
6387/**
6388 * xmlXPathCompareNodeSetString:
6389 * @ctxt: the XPath Parser context
6390 * @inf: less than (1) or greater than (0)
6391 * @strict: is the comparison strict
6392 * @arg: the node set
6393 * @s: the value
6394 *
6395 * Implement the compare operation between a nodeset and a string
6396 * @ns < @val (1, 1, ...
6397 * @ns <= @val (1, 0, ...
6398 * @ns > @val (0, 1, ...
6399 * @ns >= @val (0, 0, ...
6400 *
6401 * If one object to be compared is a node-set and the other is a string,
6402 * then the comparison will be true if and only if there is a node in
6403 * the node-set such that the result of performing the comparison on the
6404 * string-value of the node and the other string is true.
6405 *
6406 * Returns 0 or 1 depending on the results of the test.
6407 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006408static int
Owen Taylor3473f882001-02-23 17:55:21 +00006409xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6410 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6411 int i, ret = 0;
6412 xmlNodeSetPtr ns;
6413 xmlChar *str2;
6414
6415 if ((s == NULL) || (arg == NULL) ||
6416 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006417 xmlXPathReleaseObject(ctxt->context, arg);
6418 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006419 return(0);
6420 }
6421 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006422 if (ns != NULL) {
6423 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006424 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006425 if (str2 != NULL) {
6426 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006427 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006428 xmlFree(str2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006429 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006430 ret = xmlXPathCompareValues(ctxt, inf, strict);
6431 if (ret)
6432 break;
6433 }
6434 }
Owen Taylor3473f882001-02-23 17:55:21 +00006435 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006436 xmlXPathReleaseObject(ctxt->context, arg);
6437 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006438 return(ret);
6439}
6440
6441/**
6442 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006443 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00006444 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006445 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00006446 * @arg2: the second node set object
6447 *
6448 * Implement the compare operation on nodesets:
6449 *
6450 * If both objects to be compared are node-sets, then the comparison
6451 * will be true if and only if there is a node in the first node-set
6452 * and a node in the second node-set such that the result of performing
Daniel Veillard45490ae2008-07-29 09:13:19 +00006453 * the comparison on the string-values of the two nodes is true.
Owen Taylor3473f882001-02-23 17:55:21 +00006454 * ....
6455 * When neither object to be compared is a node-set and the operator
6456 * is <=, <, >= or >, then the objects are compared by converting both
6457 * objects to numbers and comparing the numbers according to IEEE 754.
6458 * ....
6459 * The number function converts its argument to a number as follows:
6460 * - a string that consists of optional whitespace followed by an
6461 * optional minus sign followed by a Number followed by whitespace
6462 * is converted to the IEEE 754 number that is nearest (according
6463 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6464 * represented by the string; any other string is converted to NaN
6465 *
6466 * Conclusion all nodes need to be converted first to their string value
Daniel Veillard45490ae2008-07-29 09:13:19 +00006467 * and then the comparison must be done when possible
Owen Taylor3473f882001-02-23 17:55:21 +00006468 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006469static int
6470xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00006471 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6472 int i, j, init = 0;
6473 double val1;
6474 double *values2;
6475 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006476 xmlNodeSetPtr ns1;
6477 xmlNodeSetPtr ns2;
6478
6479 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006480 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6481 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006482 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006483 }
Owen Taylor3473f882001-02-23 17:55:21 +00006484 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006485 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6486 xmlXPathFreeObject(arg1);
6487 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006488 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006489 }
Owen Taylor3473f882001-02-23 17:55:21 +00006490
6491 ns1 = arg1->nodesetval;
6492 ns2 = arg2->nodesetval;
6493
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006494 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006495 xmlXPathFreeObject(arg1);
6496 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006497 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006498 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006499 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006500 xmlXPathFreeObject(arg1);
6501 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006502 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006503 }
Owen Taylor3473f882001-02-23 17:55:21 +00006504
6505 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6506 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006507 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00006508 xmlXPathFreeObject(arg1);
6509 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006510 return(0);
6511 }
6512 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006513 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00006514 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00006515 continue;
6516 for (j = 0;j < ns2->nodeNr;j++) {
6517 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006518 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00006519 }
Daniel Veillardcda96922001-08-21 10:56:31 +00006520 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00006521 continue;
Daniel Veillard45490ae2008-07-29 09:13:19 +00006522 if (inf && strict)
Owen Taylor3473f882001-02-23 17:55:21 +00006523 ret = (val1 < values2[j]);
6524 else if (inf && !strict)
6525 ret = (val1 <= values2[j]);
6526 else if (!inf && strict)
6527 ret = (val1 > values2[j]);
6528 else if (!inf && !strict)
6529 ret = (val1 >= values2[j]);
6530 if (ret)
6531 break;
6532 }
6533 if (ret)
6534 break;
6535 init = 1;
6536 }
6537 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006538 xmlXPathFreeObject(arg1);
6539 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006540 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006541}
6542
6543/**
6544 * xmlXPathCompareNodeSetValue:
6545 * @ctxt: the XPath Parser context
6546 * @inf: less than (1) or greater than (0)
6547 * @strict: is the comparison strict
6548 * @arg: the node set
6549 * @val: the value
6550 *
6551 * Implement the compare operation between a nodeset and a value
6552 * @ns < @val (1, 1, ...
6553 * @ns <= @val (1, 0, ...
6554 * @ns > @val (0, 1, ...
6555 * @ns >= @val (0, 0, ...
6556 *
6557 * If one object to be compared is a node-set and the other is a boolean,
6558 * then the comparison will be true if and only if the result of performing
6559 * the comparison on the boolean and on the result of converting
6560 * the node-set to a boolean using the boolean function is true.
6561 *
6562 * Returns 0 or 1 depending on the results of the test.
6563 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006564static int
Owen Taylor3473f882001-02-23 17:55:21 +00006565xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6566 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6567 if ((val == NULL) || (arg == NULL) ||
6568 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6569 return(0);
6570
6571 switch(val->type) {
6572 case XPATH_NUMBER:
6573 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6574 case XPATH_NODESET:
6575 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006576 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00006577 case XPATH_STRING:
6578 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6579 case XPATH_BOOLEAN:
6580 valuePush(ctxt, arg);
6581 xmlXPathBooleanFunction(ctxt, 1);
6582 valuePush(ctxt, val);
6583 return(xmlXPathCompareValues(ctxt, inf, strict));
6584 default:
6585 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00006586 }
6587 return(0);
6588}
6589
6590/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006591 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00006592 * @arg: the nodeset object argument
6593 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00006594 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006595 *
6596 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6597 * If one object to be compared is a node-set and the other is a string,
6598 * then the comparison will be true if and only if there is a node in
6599 * the node-set such that the result of performing the comparison on the
6600 * string-value of the node and the other string is true.
6601 *
6602 * Returns 0 or 1 depending on the results of the test.
6603 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006604static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006605xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006606{
Owen Taylor3473f882001-02-23 17:55:21 +00006607 int i;
6608 xmlNodeSetPtr ns;
6609 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006610 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00006611
6612 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00006613 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6614 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006615 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00006616 /*
6617 * A NULL nodeset compared with a string is always false
6618 * (since there is no node equal, and no node not equal)
6619 */
6620 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00006621 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00006622 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006623 for (i = 0; i < ns->nodeNr; i++) {
6624 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6625 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6626 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6627 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006628 if (neq)
6629 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006630 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00006631 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6632 if (neq)
6633 continue;
6634 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006635 } else if (neq) {
6636 if (str2 != NULL)
6637 xmlFree(str2);
6638 return (1);
6639 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006640 if (str2 != NULL)
6641 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006642 } else if (neq)
6643 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00006644 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006645 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006646}
6647
6648/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006649 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00006650 * @arg: the nodeset object argument
6651 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00006652 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006653 *
6654 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6655 * If one object to be compared is a node-set and the other is a number,
6656 * then the comparison will be true if and only if there is a node in
6657 * the node-set such that the result of performing the comparison on the
6658 * number to be compared and on the result of converting the string-value
6659 * of that node to a number using the number function is true.
6660 *
6661 * Returns 0 or 1 depending on the results of the test.
6662 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006663static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006664xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6665 xmlXPathObjectPtr arg, double f, int neq) {
6666 int i, ret=0;
6667 xmlNodeSetPtr ns;
6668 xmlChar *str2;
6669 xmlXPathObjectPtr val;
6670 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00006671
6672 if ((arg == NULL) ||
6673 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6674 return(0);
6675
William M. Brack0c022ad2002-07-12 00:56:01 +00006676 ns = arg->nodesetval;
6677 if (ns != NULL) {
6678 for (i=0;i<ns->nodeNr;i++) {
6679 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6680 if (str2 != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006681 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
William M. Brack0c022ad2002-07-12 00:56:01 +00006682 xmlFree(str2);
6683 xmlXPathNumberFunction(ctxt, 1);
6684 val = valuePop(ctxt);
6685 v = val->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006686 xmlXPathReleaseObject(ctxt->context, val);
William M. Brack0c022ad2002-07-12 00:56:01 +00006687 if (!xmlXPathIsNaN(v)) {
6688 if ((!neq) && (v==f)) {
6689 ret = 1;
6690 break;
6691 } else if ((neq) && (v!=f)) {
6692 ret = 1;
6693 break;
6694 }
William M. Brack32f0f712005-07-14 07:00:33 +00006695 } else { /* NaN is unequal to any value */
6696 if (neq)
6697 ret = 1;
William M. Brack0c022ad2002-07-12 00:56:01 +00006698 }
6699 }
6700 }
6701 }
6702
6703 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006704}
6705
6706
6707/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006708 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00006709 * @arg1: first nodeset object argument
6710 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00006711 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006712 *
William M. Brack0c022ad2002-07-12 00:56:01 +00006713 * Implement the equal / not equal operation on XPath nodesets:
6714 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00006715 * If both objects to be compared are node-sets, then the comparison
6716 * will be true if and only if there is a node in the first node-set and
6717 * a node in the second node-set such that the result of performing the
6718 * comparison on the string-values of the two nodes is true.
6719 *
6720 * (needless to say, this is a costly operation)
6721 *
6722 * Returns 0 or 1 depending on the results of the test.
6723 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006724static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006725xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00006726 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006727 unsigned int *hashs1;
6728 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00006729 xmlChar **values1;
6730 xmlChar **values2;
6731 int ret = 0;
6732 xmlNodeSetPtr ns1;
6733 xmlNodeSetPtr ns2;
6734
6735 if ((arg1 == NULL) ||
6736 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6737 return(0);
6738 if ((arg2 == NULL) ||
6739 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6740 return(0);
6741
6742 ns1 = arg1->nodesetval;
6743 ns2 = arg2->nodesetval;
6744
Daniel Veillard911f49a2001-04-07 15:39:35 +00006745 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006746 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006747 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006748 return(0);
6749
6750 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00006751 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00006752 */
William M. Brack0c022ad2002-07-12 00:56:01 +00006753 if (neq == 0)
6754 for (i = 0;i < ns1->nodeNr;i++)
6755 for (j = 0;j < ns2->nodeNr;j++)
6756 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6757 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006758
6759 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006760 if (values1 == NULL) {
6761 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006762 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006763 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006764 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6765 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006766 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006767 xmlFree(values1);
6768 return(0);
6769 }
Owen Taylor3473f882001-02-23 17:55:21 +00006770 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6771 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6772 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006773 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006774 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00006775 xmlFree(values1);
6776 return(0);
6777 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006778 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6779 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006780 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006781 xmlFree(hashs1);
6782 xmlFree(values1);
6783 xmlFree(values2);
6784 return(0);
6785 }
Owen Taylor3473f882001-02-23 17:55:21 +00006786 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6787 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006788 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006789 for (j = 0;j < ns2->nodeNr;j++) {
6790 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006791 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006792 if (hashs1[i] != hashs2[j]) {
6793 if (neq) {
6794 ret = 1;
6795 break;
6796 }
6797 }
6798 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006799 if (values1[i] == NULL)
6800 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6801 if (values2[j] == NULL)
6802 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006803 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006804 if (ret)
6805 break;
6806 }
Owen Taylor3473f882001-02-23 17:55:21 +00006807 }
6808 if (ret)
6809 break;
6810 }
6811 for (i = 0;i < ns1->nodeNr;i++)
6812 if (values1[i] != NULL)
6813 xmlFree(values1[i]);
6814 for (j = 0;j < ns2->nodeNr;j++)
6815 if (values2[j] != NULL)
6816 xmlFree(values2[j]);
6817 xmlFree(values1);
6818 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006819 xmlFree(hashs1);
6820 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00006821 return(ret);
6822}
6823
William M. Brack0c022ad2002-07-12 00:56:01 +00006824static int
6825xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6826 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00006827 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00006828 /*
6829 *At this point we are assured neither arg1 nor arg2
6830 *is a nodeset, so we can just pick the appropriate routine.
6831 */
Owen Taylor3473f882001-02-23 17:55:21 +00006832 switch (arg1->type) {
6833 case XPATH_UNDEFINED:
6834#ifdef DEBUG_EXPR
6835 xmlGenericError(xmlGenericErrorContext,
6836 "Equal: undefined\n");
6837#endif
6838 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006839 case XPATH_BOOLEAN:
6840 switch (arg2->type) {
6841 case XPATH_UNDEFINED:
6842#ifdef DEBUG_EXPR
6843 xmlGenericError(xmlGenericErrorContext,
6844 "Equal: undefined\n");
6845#endif
6846 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006847 case XPATH_BOOLEAN:
6848#ifdef DEBUG_EXPR
6849 xmlGenericError(xmlGenericErrorContext,
6850 "Equal: %d boolean %d \n",
6851 arg1->boolval, arg2->boolval);
6852#endif
6853 ret = (arg1->boolval == arg2->boolval);
6854 break;
6855 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00006856 ret = (arg1->boolval ==
6857 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006858 break;
6859 case XPATH_STRING:
6860 if ((arg2->stringval == NULL) ||
6861 (arg2->stringval[0] == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00006862 else
Owen Taylor3473f882001-02-23 17:55:21 +00006863 ret = 1;
6864 ret = (arg1->boolval == ret);
6865 break;
6866 case XPATH_USERS:
6867 case XPATH_POINT:
6868 case XPATH_RANGE:
6869 case XPATH_LOCATIONSET:
6870 TODO
6871 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006872 case XPATH_NODESET:
6873 case XPATH_XSLT_TREE:
6874 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006875 }
6876 break;
6877 case XPATH_NUMBER:
6878 switch (arg2->type) {
6879 case XPATH_UNDEFINED:
6880#ifdef DEBUG_EXPR
6881 xmlGenericError(xmlGenericErrorContext,
6882 "Equal: undefined\n");
6883#endif
6884 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006885 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00006886 ret = (arg2->boolval==
6887 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006888 break;
6889 case XPATH_STRING:
6890 valuePush(ctxt, arg2);
6891 xmlXPathNumberFunction(ctxt, 1);
6892 arg2 = valuePop(ctxt);
6893 /* no break on purpose */
6894 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006895 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00006896 if (xmlXPathIsNaN(arg1->floatval) ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00006897 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00006898 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006899 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6900 if (xmlXPathIsInf(arg2->floatval) == 1)
6901 ret = 1;
6902 else
6903 ret = 0;
6904 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6905 if (xmlXPathIsInf(arg2->floatval) == -1)
6906 ret = 1;
6907 else
6908 ret = 0;
6909 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6910 if (xmlXPathIsInf(arg1->floatval) == 1)
6911 ret = 1;
6912 else
6913 ret = 0;
6914 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6915 if (xmlXPathIsInf(arg1->floatval) == -1)
6916 ret = 1;
6917 else
6918 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00006919 } else {
6920 ret = (arg1->floatval == arg2->floatval);
6921 }
Owen Taylor3473f882001-02-23 17:55:21 +00006922 break;
6923 case XPATH_USERS:
6924 case XPATH_POINT:
6925 case XPATH_RANGE:
6926 case XPATH_LOCATIONSET:
6927 TODO
6928 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006929 case XPATH_NODESET:
6930 case XPATH_XSLT_TREE:
6931 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006932 }
6933 break;
6934 case XPATH_STRING:
6935 switch (arg2->type) {
6936 case XPATH_UNDEFINED:
6937#ifdef DEBUG_EXPR
6938 xmlGenericError(xmlGenericErrorContext,
6939 "Equal: undefined\n");
6940#endif
6941 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006942 case XPATH_BOOLEAN:
6943 if ((arg1->stringval == NULL) ||
6944 (arg1->stringval[0] == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00006945 else
Owen Taylor3473f882001-02-23 17:55:21 +00006946 ret = 1;
6947 ret = (arg2->boolval == ret);
6948 break;
6949 case XPATH_STRING:
6950 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6951 break;
6952 case XPATH_NUMBER:
6953 valuePush(ctxt, arg1);
6954 xmlXPathNumberFunction(ctxt, 1);
6955 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006956 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00006957 if (xmlXPathIsNaN(arg1->floatval) ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00006958 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00006959 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006960 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6961 if (xmlXPathIsInf(arg2->floatval) == 1)
6962 ret = 1;
6963 else
6964 ret = 0;
6965 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6966 if (xmlXPathIsInf(arg2->floatval) == -1)
6967 ret = 1;
6968 else
6969 ret = 0;
6970 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6971 if (xmlXPathIsInf(arg1->floatval) == 1)
6972 ret = 1;
6973 else
6974 ret = 0;
6975 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6976 if (xmlXPathIsInf(arg1->floatval) == -1)
6977 ret = 1;
6978 else
6979 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00006980 } else {
6981 ret = (arg1->floatval == arg2->floatval);
6982 }
Owen Taylor3473f882001-02-23 17:55:21 +00006983 break;
6984 case XPATH_USERS:
6985 case XPATH_POINT:
6986 case XPATH_RANGE:
6987 case XPATH_LOCATIONSET:
6988 TODO
6989 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006990 case XPATH_NODESET:
6991 case XPATH_XSLT_TREE:
6992 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006993 }
6994 break;
6995 case XPATH_USERS:
6996 case XPATH_POINT:
6997 case XPATH_RANGE:
6998 case XPATH_LOCATIONSET:
6999 TODO
7000 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007001 case XPATH_NODESET:
7002 case XPATH_XSLT_TREE:
7003 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007004 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007005 xmlXPathReleaseObject(ctxt->context, arg1);
7006 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007007 return(ret);
7008}
7009
William M. Brack0c022ad2002-07-12 00:56:01 +00007010/**
7011 * xmlXPathEqualValues:
7012 * @ctxt: the XPath Parser context
7013 *
7014 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7015 *
7016 * Returns 0 or 1 depending on the results of the test.
7017 */
7018int
7019xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7020 xmlXPathObjectPtr arg1, arg2, argtmp;
7021 int ret = 0;
7022
Daniel Veillard6128c012004-11-08 17:16:15 +00007023 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007024 arg2 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007025 arg1 = valuePop(ctxt);
7026 if ((arg1 == NULL) || (arg2 == NULL)) {
7027 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007028 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007029 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007030 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007031 XP_ERROR0(XPATH_INVALID_OPERAND);
7032 }
7033
7034 if (arg1 == arg2) {
7035#ifdef DEBUG_EXPR
7036 xmlGenericError(xmlGenericErrorContext,
7037 "Equal: by pointer\n");
7038#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00007039 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007040 return(1);
7041 }
7042
7043 /*
7044 *If either argument is a nodeset, it's a 'special case'
7045 */
7046 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7047 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7048 /*
7049 *Hack it to assure arg1 is the nodeset
7050 */
7051 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7052 argtmp = arg2;
7053 arg2 = arg1;
7054 arg1 = argtmp;
7055 }
7056 switch (arg2->type) {
7057 case XPATH_UNDEFINED:
7058#ifdef DEBUG_EXPR
7059 xmlGenericError(xmlGenericErrorContext,
7060 "Equal: undefined\n");
7061#endif
7062 break;
7063 case XPATH_NODESET:
7064 case XPATH_XSLT_TREE:
7065 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7066 break;
7067 case XPATH_BOOLEAN:
7068 if ((arg1->nodesetval == NULL) ||
7069 (arg1->nodesetval->nodeNr == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007070 else
William M. Brack0c022ad2002-07-12 00:56:01 +00007071 ret = 1;
7072 ret = (ret == arg2->boolval);
7073 break;
7074 case XPATH_NUMBER:
7075 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7076 break;
7077 case XPATH_STRING:
7078 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7079 break;
7080 case XPATH_USERS:
7081 case XPATH_POINT:
7082 case XPATH_RANGE:
7083 case XPATH_LOCATIONSET:
7084 TODO
7085 break;
7086 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007087 xmlXPathReleaseObject(ctxt->context, arg1);
7088 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007089 return(ret);
7090 }
7091
7092 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7093}
7094
7095/**
7096 * xmlXPathNotEqualValues:
7097 * @ctxt: the XPath Parser context
7098 *
7099 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7100 *
7101 * Returns 0 or 1 depending on the results of the test.
7102 */
7103int
7104xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7105 xmlXPathObjectPtr arg1, arg2, argtmp;
7106 int ret = 0;
7107
Daniel Veillard6128c012004-11-08 17:16:15 +00007108 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007109 arg2 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007110 arg1 = valuePop(ctxt);
7111 if ((arg1 == NULL) || (arg2 == NULL)) {
7112 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007113 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007114 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007115 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007116 XP_ERROR0(XPATH_INVALID_OPERAND);
7117 }
7118
7119 if (arg1 == arg2) {
7120#ifdef DEBUG_EXPR
7121 xmlGenericError(xmlGenericErrorContext,
7122 "NotEqual: by pointer\n");
7123#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007124 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007125 return(0);
7126 }
7127
7128 /*
7129 *If either argument is a nodeset, it's a 'special case'
7130 */
7131 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7132 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7133 /*
7134 *Hack it to assure arg1 is the nodeset
7135 */
7136 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7137 argtmp = arg2;
7138 arg2 = arg1;
7139 arg1 = argtmp;
7140 }
7141 switch (arg2->type) {
7142 case XPATH_UNDEFINED:
7143#ifdef DEBUG_EXPR
7144 xmlGenericError(xmlGenericErrorContext,
7145 "NotEqual: undefined\n");
7146#endif
7147 break;
7148 case XPATH_NODESET:
7149 case XPATH_XSLT_TREE:
7150 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7151 break;
7152 case XPATH_BOOLEAN:
7153 if ((arg1->nodesetval == NULL) ||
7154 (arg1->nodesetval->nodeNr == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007155 else
William M. Brack0c022ad2002-07-12 00:56:01 +00007156 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00007157 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00007158 break;
7159 case XPATH_NUMBER:
7160 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7161 break;
7162 case XPATH_STRING:
7163 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7164 break;
7165 case XPATH_USERS:
7166 case XPATH_POINT:
7167 case XPATH_RANGE:
7168 case XPATH_LOCATIONSET:
7169 TODO
7170 break;
7171 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007172 xmlXPathReleaseObject(ctxt->context, arg1);
7173 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007174 return(ret);
7175 }
7176
7177 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7178}
Owen Taylor3473f882001-02-23 17:55:21 +00007179
7180/**
7181 * xmlXPathCompareValues:
7182 * @ctxt: the XPath Parser context
7183 * @inf: less than (1) or greater than (0)
7184 * @strict: is the comparison strict
7185 *
Daniel Veillard45490ae2008-07-29 09:13:19 +00007186 * Implement the compare operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007187 * @arg1 < @arg2 (1, 1, ...
7188 * @arg1 <= @arg2 (1, 0, ...
7189 * @arg1 > @arg2 (0, 1, ...
7190 * @arg1 >= @arg2 (0, 0, ...
7191 *
7192 * When neither object to be compared is a node-set and the operator is
7193 * <=, <, >=, >, then the objects are compared by converted both objects
7194 * to numbers and comparing the numbers according to IEEE 754. The <
7195 * comparison will be true if and only if the first number is less than the
7196 * second number. The <= comparison will be true if and only if the first
7197 * number is less than or equal to the second number. The > comparison
7198 * will be true if and only if the first number is greater than the second
7199 * number. The >= comparison will be true if and only if the first number
7200 * is greater than or equal to the second number.
7201 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007202 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00007203 */
7204int
7205xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007206 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007207 xmlXPathObjectPtr arg1, arg2;
7208
Daniel Veillard6128c012004-11-08 17:16:15 +00007209 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007210 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007211 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007212 if ((arg1 == NULL) || (arg2 == NULL)) {
7213 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007214 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007215 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007216 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007217 XP_ERROR0(XPATH_INVALID_OPERAND);
7218 }
7219
William M. Brack0c022ad2002-07-12 00:56:01 +00007220 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7221 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
William M. Brackd6e347e2005-04-15 01:34:41 +00007222 /*
7223 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7224 * are not freed from within this routine; they will be freed from the
7225 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7226 */
William M. Brack0c022ad2002-07-12 00:56:01 +00007227 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7228 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007229 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007230 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00007231 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007232 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7233 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007234 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007235 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7236 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00007237 }
7238 }
7239 return(ret);
7240 }
7241
7242 if (arg1->type != XPATH_NUMBER) {
7243 valuePush(ctxt, arg1);
7244 xmlXPathNumberFunction(ctxt, 1);
7245 arg1 = valuePop(ctxt);
7246 }
7247 if (arg1->type != XPATH_NUMBER) {
7248 xmlXPathFreeObject(arg1);
7249 xmlXPathFreeObject(arg2);
7250 XP_ERROR0(XPATH_INVALID_OPERAND);
7251 }
7252 if (arg2->type != XPATH_NUMBER) {
7253 valuePush(ctxt, arg2);
7254 xmlXPathNumberFunction(ctxt, 1);
7255 arg2 = valuePop(ctxt);
7256 }
7257 if (arg2->type != XPATH_NUMBER) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007258 xmlXPathReleaseObject(ctxt->context, arg1);
7259 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007260 XP_ERROR0(XPATH_INVALID_OPERAND);
7261 }
7262 /*
7263 * Add tests for infinity and nan
7264 * => feedback on 3.4 for Inf and NaN
7265 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007266 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00007267 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007268 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007269 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007270 arg1i=xmlXPathIsInf(arg1->floatval);
7271 arg2i=xmlXPathIsInf(arg2->floatval);
7272 if (inf && strict) {
7273 if ((arg1i == -1 && arg2i != -1) ||
7274 (arg2i == 1 && arg1i != 1)) {
7275 ret = 1;
7276 } else if (arg1i == 0 && arg2i == 0) {
7277 ret = (arg1->floatval < arg2->floatval);
7278 } else {
7279 ret = 0;
7280 }
7281 }
7282 else if (inf && !strict) {
7283 if (arg1i == -1 || arg2i == 1) {
7284 ret = 1;
7285 } else if (arg1i == 0 && arg2i == 0) {
7286 ret = (arg1->floatval <= arg2->floatval);
7287 } else {
7288 ret = 0;
7289 }
7290 }
7291 else if (!inf && strict) {
7292 if ((arg1i == 1 && arg2i != 1) ||
7293 (arg2i == -1 && arg1i != -1)) {
7294 ret = 1;
7295 } else if (arg1i == 0 && arg2i == 0) {
7296 ret = (arg1->floatval > arg2->floatval);
7297 } else {
7298 ret = 0;
7299 }
7300 }
7301 else if (!inf && !strict) {
7302 if (arg1i == 1 || arg2i == -1) {
7303 ret = 1;
7304 } else if (arg1i == 0 && arg2i == 0) {
7305 ret = (arg1->floatval >= arg2->floatval);
7306 } else {
7307 ret = 0;
7308 }
7309 }
Daniel Veillard21458c82002-03-27 16:12:22 +00007310 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007311 xmlXPathReleaseObject(ctxt->context, arg1);
7312 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007313 return(ret);
7314}
7315
7316/**
7317 * xmlXPathValueFlipSign:
7318 * @ctxt: the XPath Parser context
7319 *
7320 * Implement the unary - operation on an XPath object
7321 * The numeric operators convert their operands to numbers as if
7322 * by calling the number function.
7323 */
7324void
7325xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007326 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007327 CAST_TO_NUMBER;
7328 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007329 if (xmlXPathIsNaN(ctxt->value->floatval))
7330 ctxt->value->floatval=xmlXPathNAN;
7331 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7332 ctxt->value->floatval=xmlXPathNINF;
7333 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7334 ctxt->value->floatval=xmlXPathPINF;
7335 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007336 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7337 ctxt->value->floatval = xmlXPathNZERO;
7338 else
7339 ctxt->value->floatval = 0;
7340 }
7341 else
7342 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00007343}
7344
7345/**
7346 * xmlXPathAddValues:
7347 * @ctxt: the XPath Parser context
7348 *
7349 * Implement the add operation on XPath objects:
7350 * The numeric operators convert their operands to numbers as if
7351 * by calling the number function.
7352 */
7353void
7354xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7355 xmlXPathObjectPtr arg;
7356 double val;
7357
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007358 arg = valuePop(ctxt);
7359 if (arg == NULL)
7360 XP_ERROR(XPATH_INVALID_OPERAND);
7361 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007362 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007363 CAST_TO_NUMBER;
7364 CHECK_TYPE(XPATH_NUMBER);
7365 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00007366}
7367
7368/**
7369 * xmlXPathSubValues:
7370 * @ctxt: the XPath Parser context
7371 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007372 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007373 * The numeric operators convert their operands to numbers as if
7374 * by calling the number function.
7375 */
7376void
7377xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7378 xmlXPathObjectPtr arg;
7379 double val;
7380
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007381 arg = valuePop(ctxt);
7382 if (arg == NULL)
7383 XP_ERROR(XPATH_INVALID_OPERAND);
7384 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007385 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007386 CAST_TO_NUMBER;
7387 CHECK_TYPE(XPATH_NUMBER);
7388 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007389}
7390
7391/**
7392 * xmlXPathMultValues:
7393 * @ctxt: the XPath Parser context
7394 *
7395 * Implement the multiply operation on XPath objects:
7396 * The numeric operators convert their operands to numbers as if
7397 * by calling the number function.
7398 */
7399void
7400xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7401 xmlXPathObjectPtr arg;
7402 double val;
7403
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007404 arg = valuePop(ctxt);
7405 if (arg == NULL)
7406 XP_ERROR(XPATH_INVALID_OPERAND);
7407 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007408 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007409 CAST_TO_NUMBER;
7410 CHECK_TYPE(XPATH_NUMBER);
7411 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007412}
7413
7414/**
7415 * xmlXPathDivValues:
7416 * @ctxt: the XPath Parser context
7417 *
7418 * Implement the div operation on XPath objects @arg1 / @arg2:
7419 * The numeric operators convert their operands to numbers as if
7420 * by calling the number function.
7421 */
7422void
7423xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7424 xmlXPathObjectPtr arg;
7425 double val;
7426
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007427 arg = valuePop(ctxt);
7428 if (arg == NULL)
7429 XP_ERROR(XPATH_INVALID_OPERAND);
7430 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007431 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007432 CAST_TO_NUMBER;
7433 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007434 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7435 ctxt->value->floatval = xmlXPathNAN;
7436 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007437 if (ctxt->value->floatval == 0)
7438 ctxt->value->floatval = xmlXPathNAN;
7439 else if (ctxt->value->floatval > 0)
7440 ctxt->value->floatval = xmlXPathNINF;
7441 else if (ctxt->value->floatval < 0)
7442 ctxt->value->floatval = xmlXPathPINF;
7443 }
7444 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007445 if (ctxt->value->floatval == 0)
7446 ctxt->value->floatval = xmlXPathNAN;
7447 else if (ctxt->value->floatval > 0)
7448 ctxt->value->floatval = xmlXPathPINF;
7449 else if (ctxt->value->floatval < 0)
7450 ctxt->value->floatval = xmlXPathNINF;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007451 } else
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007452 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007453}
7454
7455/**
7456 * xmlXPathModValues:
7457 * @ctxt: the XPath Parser context
7458 *
7459 * Implement the mod operation on XPath objects: @arg1 / @arg2
7460 * The numeric operators convert their operands to numbers as if
7461 * by calling the number function.
7462 */
7463void
7464xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7465 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00007466 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00007467
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007468 arg = valuePop(ctxt);
7469 if (arg == NULL)
7470 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007471 arg2 = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007472 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007473 CAST_TO_NUMBER;
7474 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007475 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00007476 if (arg2 == 0)
7477 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007478 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00007479 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007480 }
Owen Taylor3473f882001-02-23 17:55:21 +00007481}
7482
7483/************************************************************************
7484 * *
7485 * The traversal functions *
7486 * *
7487 ************************************************************************/
7488
Owen Taylor3473f882001-02-23 17:55:21 +00007489/*
7490 * A traversal function enumerates nodes along an axis.
7491 * Initially it must be called with NULL, and it indicates
7492 * termination on the axis by returning NULL.
7493 */
7494typedef xmlNodePtr (*xmlXPathTraversalFunction)
7495 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7496
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007497/*
7498 * xmlXPathTraversalFunctionExt:
7499 * A traversal function enumerates nodes along an axis.
7500 * Initially it must be called with NULL, and it indicates
7501 * termination on the axis by returning NULL.
7502 * The context node of the traversal is specified via @contextNode.
7503 */
7504typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7505 (xmlNodePtr cur, xmlNodePtr contextNode);
7506
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00007507/*
7508 * xmlXPathNodeSetMergeFunction:
7509 * Used for merging node sets in xmlXPathCollectAndTest().
7510 */
7511typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7512 (xmlNodeSetPtr, xmlNodeSetPtr, int);
7513
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007514
Owen Taylor3473f882001-02-23 17:55:21 +00007515/**
7516 * xmlXPathNextSelf:
7517 * @ctxt: the XPath Parser context
7518 * @cur: the current node in the traversal
7519 *
7520 * Traversal function for the "self" direction
7521 * The self axis contains just the context node itself
7522 *
7523 * Returns the next element following that axis
7524 */
7525xmlNodePtr
7526xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007527 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007528 if (cur == NULL)
7529 return(ctxt->context->node);
7530 return(NULL);
7531}
7532
7533/**
7534 * xmlXPathNextChild:
7535 * @ctxt: the XPath Parser context
7536 * @cur: the current node in the traversal
7537 *
7538 * Traversal function for the "child" direction
7539 * The child axis contains the children of the context node in document order.
7540 *
7541 * Returns the next element following that axis
7542 */
7543xmlNodePtr
7544xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007545 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007546 if (cur == NULL) {
7547 if (ctxt->context->node == NULL) return(NULL);
7548 switch (ctxt->context->node->type) {
7549 case XML_ELEMENT_NODE:
7550 case XML_TEXT_NODE:
7551 case XML_CDATA_SECTION_NODE:
7552 case XML_ENTITY_REF_NODE:
7553 case XML_ENTITY_NODE:
7554 case XML_PI_NODE:
7555 case XML_COMMENT_NODE:
7556 case XML_NOTATION_NODE:
7557 case XML_DTD_NODE:
7558 return(ctxt->context->node->children);
7559 case XML_DOCUMENT_NODE:
7560 case XML_DOCUMENT_TYPE_NODE:
7561 case XML_DOCUMENT_FRAG_NODE:
7562 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007563#ifdef LIBXML_DOCB_ENABLED
7564 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007565#endif
7566 return(((xmlDocPtr) ctxt->context->node)->children);
7567 case XML_ELEMENT_DECL:
7568 case XML_ATTRIBUTE_DECL:
7569 case XML_ENTITY_DECL:
7570 case XML_ATTRIBUTE_NODE:
7571 case XML_NAMESPACE_DECL:
7572 case XML_XINCLUDE_START:
7573 case XML_XINCLUDE_END:
7574 return(NULL);
7575 }
7576 return(NULL);
7577 }
7578 if ((cur->type == XML_DOCUMENT_NODE) ||
7579 (cur->type == XML_HTML_DOCUMENT_NODE))
7580 return(NULL);
7581 return(cur->next);
7582}
7583
7584/**
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00007585 * xmlXPathNextChildElement:
7586 * @ctxt: the XPath Parser context
7587 * @cur: the current node in the traversal
7588 *
7589 * Traversal function for the "child" direction and nodes of type element.
7590 * The child axis contains the children of the context node in document order.
7591 *
7592 * Returns the next element following that axis
7593 */
7594static xmlNodePtr
7595xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7596 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7597 if (cur == NULL) {
7598 cur = ctxt->context->node;
7599 if (cur == NULL) return(NULL);
7600 /*
7601 * Get the first element child.
7602 */
7603 switch (cur->type) {
7604 case XML_ELEMENT_NODE:
7605 case XML_DOCUMENT_FRAG_NODE:
7606 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7607 case XML_ENTITY_NODE:
7608 cur = cur->children;
7609 if (cur != NULL) {
7610 if (cur->type == XML_ELEMENT_NODE)
7611 return(cur);
7612 do {
7613 cur = cur->next;
7614 } while ((cur != NULL) &&
7615 (cur->type != XML_ELEMENT_NODE));
7616 return(cur);
7617 }
7618 return(NULL);
7619 case XML_DOCUMENT_NODE:
7620 case XML_HTML_DOCUMENT_NODE:
7621#ifdef LIBXML_DOCB_ENABLED
7622 case XML_DOCB_DOCUMENT_NODE:
7623#endif
7624 return(xmlDocGetRootElement((xmlDocPtr) cur));
7625 default:
7626 return(NULL);
7627 }
7628 return(NULL);
7629 }
7630 /*
7631 * Get the next sibling element node.
7632 */
7633 switch (cur->type) {
7634 case XML_ELEMENT_NODE:
7635 case XML_TEXT_NODE:
7636 case XML_ENTITY_REF_NODE:
7637 case XML_ENTITY_NODE:
7638 case XML_CDATA_SECTION_NODE:
7639 case XML_PI_NODE:
7640 case XML_COMMENT_NODE:
7641 case XML_XINCLUDE_END:
7642 break;
7643 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7644 default:
7645 return(NULL);
7646 }
7647 if (cur->next != NULL) {
7648 if (cur->next->type == XML_ELEMENT_NODE)
7649 return(cur->next);
7650 cur = cur->next;
7651 do {
7652 cur = cur->next;
7653 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7654 return(cur);
7655 }
7656 return(NULL);
7657}
7658
7659/**
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007660 * xmlXPathNextDescendantOrSelfElemParent:
7661 * @ctxt: the XPath Parser context
7662 * @cur: the current node in the traversal
7663 *
7664 * Traversal function for the "descendant-or-self" axis.
7665 * Additionally it returns only nodes which can be parents of
7666 * element nodes.
7667 *
7668 *
7669 * Returns the next element following that axis
7670 */
7671static xmlNodePtr
7672xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7673 xmlNodePtr contextNode)
7674{
7675 if (cur == NULL) {
7676 if (contextNode == NULL)
7677 return(NULL);
7678 switch (contextNode->type) {
7679 case XML_ELEMENT_NODE:
7680 case XML_XINCLUDE_START:
7681 case XML_DOCUMENT_FRAG_NODE:
7682 case XML_DOCUMENT_NODE:
7683#ifdef LIBXML_DOCB_ENABLED
7684 case XML_DOCB_DOCUMENT_NODE:
7685#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00007686 case XML_HTML_DOCUMENT_NODE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007687 return(contextNode);
7688 default:
Daniel Veillard45490ae2008-07-29 09:13:19 +00007689 return(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007690 }
7691 return(NULL);
7692 } else {
7693 xmlNodePtr start = cur;
7694
7695 while (cur != NULL) {
7696 switch (cur->type) {
7697 case XML_ELEMENT_NODE:
7698 /* TODO: OK to have XInclude here? */
7699 case XML_XINCLUDE_START:
Daniel Veillard45490ae2008-07-29 09:13:19 +00007700 case XML_DOCUMENT_FRAG_NODE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007701 if (cur != start)
7702 return(cur);
7703 if (cur->children != NULL) {
7704 cur = cur->children;
7705 continue;
7706 }
7707 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007708 /* Not sure if we need those here. */
7709 case XML_DOCUMENT_NODE:
Daniel Veillard17970a72006-10-26 08:55:47 +00007710#ifdef LIBXML_DOCB_ENABLED
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007711 case XML_DOCB_DOCUMENT_NODE:
7712#endif
7713 case XML_HTML_DOCUMENT_NODE:
7714 if (cur != start)
7715 return(cur);
7716 return(xmlDocGetRootElement((xmlDocPtr) cur));
7717 default:
7718 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007719 }
7720
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007721next_sibling:
7722 if ((cur == NULL) || (cur == contextNode))
Daniel Veillard45490ae2008-07-29 09:13:19 +00007723 return(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007724 if (cur->next != NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00007725 cur = cur->next;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007726 } else {
7727 cur = cur->parent;
7728 goto next_sibling;
7729 }
7730 }
7731 }
7732 return(NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007733}
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007734
7735/**
Owen Taylor3473f882001-02-23 17:55:21 +00007736 * xmlXPathNextDescendant:
7737 * @ctxt: the XPath Parser context
7738 * @cur: the current node in the traversal
7739 *
7740 * Traversal function for the "descendant" direction
7741 * the descendant axis contains the descendants of the context node in document
7742 * order; a descendant is a child or a child of a child and so on.
7743 *
7744 * Returns the next element following that axis
7745 */
7746xmlNodePtr
7747xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007748 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007749 if (cur == NULL) {
7750 if (ctxt->context->node == NULL)
7751 return(NULL);
7752 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7753 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7754 return(NULL);
7755
7756 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7757 return(ctxt->context->doc->children);
7758 return(ctxt->context->node->children);
7759 }
7760
Daniel Veillard567e1b42001-08-01 15:53:47 +00007761 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007762 /*
7763 * Do not descend on entities declarations
7764 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00007765 if (cur->children->type != XML_ENTITY_DECL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007766 cur = cur->children;
7767 /*
7768 * Skip DTDs
7769 */
7770 if (cur->type != XML_DTD_NODE)
7771 return(cur);
7772 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00007773 }
7774
7775 if (cur == ctxt->context->node) return(NULL);
7776
Daniel Veillard68e9e742002-11-16 15:35:11 +00007777 while (cur->next != NULL) {
7778 cur = cur->next;
7779 if ((cur->type != XML_ENTITY_DECL) &&
7780 (cur->type != XML_DTD_NODE))
7781 return(cur);
7782 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00007783
Owen Taylor3473f882001-02-23 17:55:21 +00007784 do {
7785 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00007786 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00007787 if (cur == ctxt->context->node) return(NULL);
7788 if (cur->next != NULL) {
7789 cur = cur->next;
7790 return(cur);
7791 }
7792 } while (cur != NULL);
7793 return(cur);
7794}
7795
7796/**
7797 * xmlXPathNextDescendantOrSelf:
7798 * @ctxt: the XPath Parser context
7799 * @cur: the current node in the traversal
7800 *
7801 * Traversal function for the "descendant-or-self" direction
7802 * the descendant-or-self axis contains the context node and the descendants
7803 * of the context node in document order; thus the context node is the first
7804 * node on the axis, and the first child of the context node is the second node
7805 * on the axis
7806 *
7807 * Returns the next element following that axis
7808 */
7809xmlNodePtr
7810xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007811 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007812 if (cur == NULL) {
7813 if (ctxt->context->node == NULL)
7814 return(NULL);
7815 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7816 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7817 return(NULL);
7818 return(ctxt->context->node);
7819 }
7820
7821 return(xmlXPathNextDescendant(ctxt, cur));
7822}
7823
7824/**
7825 * xmlXPathNextParent:
7826 * @ctxt: the XPath Parser context
7827 * @cur: the current node in the traversal
7828 *
7829 * Traversal function for the "parent" direction
7830 * The parent axis contains the parent of the context node, if there is one.
7831 *
7832 * Returns the next element following that axis
7833 */
7834xmlNodePtr
7835xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007836 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007837 /*
7838 * the parent of an attribute or namespace node is the element
7839 * to which the attribute or namespace node is attached
7840 * Namespace handling !!!
7841 */
7842 if (cur == NULL) {
7843 if (ctxt->context->node == NULL) return(NULL);
7844 switch (ctxt->context->node->type) {
7845 case XML_ELEMENT_NODE:
7846 case XML_TEXT_NODE:
7847 case XML_CDATA_SECTION_NODE:
7848 case XML_ENTITY_REF_NODE:
7849 case XML_ENTITY_NODE:
7850 case XML_PI_NODE:
7851 case XML_COMMENT_NODE:
7852 case XML_NOTATION_NODE:
7853 case XML_DTD_NODE:
7854 case XML_ELEMENT_DECL:
7855 case XML_ATTRIBUTE_DECL:
7856 case XML_XINCLUDE_START:
7857 case XML_XINCLUDE_END:
7858 case XML_ENTITY_DECL:
7859 if (ctxt->context->node->parent == NULL)
7860 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007861 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007862 ((ctxt->context->node->parent->name[0] == ' ') ||
7863 (xmlStrEqual(ctxt->context->node->parent->name,
7864 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007865 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007866 return(ctxt->context->node->parent);
7867 case XML_ATTRIBUTE_NODE: {
7868 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7869
7870 return(att->parent);
7871 }
7872 case XML_DOCUMENT_NODE:
7873 case XML_DOCUMENT_TYPE_NODE:
7874 case XML_DOCUMENT_FRAG_NODE:
7875 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007876#ifdef LIBXML_DOCB_ENABLED
7877 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007878#endif
7879 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007880 case XML_NAMESPACE_DECL: {
7881 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007882
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007883 if ((ns->next != NULL) &&
7884 (ns->next->type != XML_NAMESPACE_DECL))
7885 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00007886 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007887 }
Owen Taylor3473f882001-02-23 17:55:21 +00007888 }
7889 }
7890 return(NULL);
7891}
7892
7893/**
7894 * xmlXPathNextAncestor:
7895 * @ctxt: the XPath Parser context
7896 * @cur: the current node in the traversal
7897 *
7898 * Traversal function for the "ancestor" direction
7899 * the ancestor axis contains the ancestors of the context node; the ancestors
7900 * of the context node consist of the parent of context node and the parent's
7901 * parent and so on; the nodes are ordered in reverse document order; thus the
7902 * parent is the first node on the axis, and the parent's parent is the second
7903 * node on the axis
7904 *
7905 * Returns the next element following that axis
7906 */
7907xmlNodePtr
7908xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007909 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007910 /*
7911 * the parent of an attribute or namespace node is the element
7912 * to which the attribute or namespace node is attached
7913 * !!!!!!!!!!!!!
7914 */
7915 if (cur == NULL) {
7916 if (ctxt->context->node == NULL) return(NULL);
7917 switch (ctxt->context->node->type) {
7918 case XML_ELEMENT_NODE:
7919 case XML_TEXT_NODE:
7920 case XML_CDATA_SECTION_NODE:
7921 case XML_ENTITY_REF_NODE:
7922 case XML_ENTITY_NODE:
7923 case XML_PI_NODE:
7924 case XML_COMMENT_NODE:
7925 case XML_DTD_NODE:
7926 case XML_ELEMENT_DECL:
7927 case XML_ATTRIBUTE_DECL:
7928 case XML_ENTITY_DECL:
7929 case XML_NOTATION_NODE:
7930 case XML_XINCLUDE_START:
7931 case XML_XINCLUDE_END:
7932 if (ctxt->context->node->parent == NULL)
7933 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007934 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007935 ((ctxt->context->node->parent->name[0] == ' ') ||
7936 (xmlStrEqual(ctxt->context->node->parent->name,
7937 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007938 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007939 return(ctxt->context->node->parent);
7940 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007941 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00007942
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007943 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00007944 }
7945 case XML_DOCUMENT_NODE:
7946 case XML_DOCUMENT_TYPE_NODE:
7947 case XML_DOCUMENT_FRAG_NODE:
7948 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007949#ifdef LIBXML_DOCB_ENABLED
7950 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007951#endif
7952 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007953 case XML_NAMESPACE_DECL: {
7954 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007955
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007956 if ((ns->next != NULL) &&
7957 (ns->next->type != XML_NAMESPACE_DECL))
7958 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00007959 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00007960 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007961 }
Owen Taylor3473f882001-02-23 17:55:21 +00007962 }
7963 return(NULL);
7964 }
7965 if (cur == ctxt->context->doc->children)
7966 return((xmlNodePtr) ctxt->context->doc);
7967 if (cur == (xmlNodePtr) ctxt->context->doc)
7968 return(NULL);
7969 switch (cur->type) {
7970 case XML_ELEMENT_NODE:
7971 case XML_TEXT_NODE:
7972 case XML_CDATA_SECTION_NODE:
7973 case XML_ENTITY_REF_NODE:
7974 case XML_ENTITY_NODE:
7975 case XML_PI_NODE:
7976 case XML_COMMENT_NODE:
7977 case XML_NOTATION_NODE:
7978 case XML_DTD_NODE:
7979 case XML_ELEMENT_DECL:
7980 case XML_ATTRIBUTE_DECL:
7981 case XML_ENTITY_DECL:
7982 case XML_XINCLUDE_START:
7983 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007984 if (cur->parent == NULL)
7985 return(NULL);
7986 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007987 ((cur->parent->name[0] == ' ') ||
7988 (xmlStrEqual(cur->parent->name,
7989 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007990 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007991 return(cur->parent);
7992 case XML_ATTRIBUTE_NODE: {
7993 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7994
7995 return(att->parent);
7996 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00007997 case XML_NAMESPACE_DECL: {
7998 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007999
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008000 if ((ns->next != NULL) &&
8001 (ns->next->type != XML_NAMESPACE_DECL))
8002 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00008003 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008004 return(NULL);
8005 }
Owen Taylor3473f882001-02-23 17:55:21 +00008006 case XML_DOCUMENT_NODE:
8007 case XML_DOCUMENT_TYPE_NODE:
8008 case XML_DOCUMENT_FRAG_NODE:
8009 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00008010#ifdef LIBXML_DOCB_ENABLED
8011 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00008012#endif
8013 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008014 }
8015 return(NULL);
8016}
8017
8018/**
8019 * xmlXPathNextAncestorOrSelf:
8020 * @ctxt: the XPath Parser context
8021 * @cur: the current node in the traversal
8022 *
8023 * Traversal function for the "ancestor-or-self" direction
8024 * he ancestor-or-self axis contains the context node and ancestors of
8025 * the context node in reverse document order; thus the context node is
8026 * the first node on the axis, and the context node's parent the second;
8027 * parent here is defined the same as with the parent axis.
8028 *
8029 * Returns the next element following that axis
8030 */
8031xmlNodePtr
8032xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008033 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008034 if (cur == NULL)
8035 return(ctxt->context->node);
8036 return(xmlXPathNextAncestor(ctxt, cur));
8037}
8038
8039/**
8040 * xmlXPathNextFollowingSibling:
8041 * @ctxt: the XPath Parser context
8042 * @cur: the current node in the traversal
8043 *
8044 * Traversal function for the "following-sibling" direction
8045 * The following-sibling axis contains the following siblings of the context
8046 * node in document order.
8047 *
8048 * Returns the next element following that axis
8049 */
8050xmlNodePtr
8051xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008052 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008053 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8054 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8055 return(NULL);
8056 if (cur == (xmlNodePtr) ctxt->context->doc)
8057 return(NULL);
8058 if (cur == NULL)
8059 return(ctxt->context->node->next);
8060 return(cur->next);
8061}
8062
8063/**
8064 * xmlXPathNextPrecedingSibling:
8065 * @ctxt: the XPath Parser context
8066 * @cur: the current node in the traversal
8067 *
8068 * Traversal function for the "preceding-sibling" direction
8069 * The preceding-sibling axis contains the preceding siblings of the context
8070 * node in reverse document order; the first preceding sibling is first on the
8071 * axis; the sibling preceding that node is the second on the axis and so on.
8072 *
8073 * Returns the next element following that axis
8074 */
8075xmlNodePtr
8076xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008077 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008078 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8079 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8080 return(NULL);
8081 if (cur == (xmlNodePtr) ctxt->context->doc)
8082 return(NULL);
8083 if (cur == NULL)
8084 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008085 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8086 cur = cur->prev;
8087 if (cur == NULL)
8088 return(ctxt->context->node->prev);
8089 }
Owen Taylor3473f882001-02-23 17:55:21 +00008090 return(cur->prev);
8091}
8092
8093/**
8094 * xmlXPathNextFollowing:
8095 * @ctxt: the XPath Parser context
8096 * @cur: the current node in the traversal
8097 *
8098 * Traversal function for the "following" direction
8099 * The following axis contains all nodes in the same document as the context
8100 * node that are after the context node in document order, excluding any
8101 * descendants and excluding attribute nodes and namespace nodes; the nodes
8102 * are ordered in document order
8103 *
8104 * Returns the next element following that axis
8105 */
8106xmlNodePtr
8107xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008108 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008109 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
8110 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8111 return(cur->children);
8112
8113 if (cur == NULL) {
8114 cur = ctxt->context->node;
8115 if (cur->type == XML_NAMESPACE_DECL)
Daniel Veillard91d19752010-10-15 14:30:52 +02008116 return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008117 if (cur->type == XML_ATTRIBUTE_NODE)
8118 cur = cur->parent;
Daniel Veillard91d19752010-10-15 14:30:52 +02008119 }
Owen Taylor3473f882001-02-23 17:55:21 +00008120 if (cur == NULL) return(NULL) ; /* ERROR */
8121 if (cur->next != NULL) return(cur->next) ;
8122 do {
8123 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00008124 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00008125 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8126 if (cur->next != NULL) return(cur->next);
8127 } while (cur != NULL);
8128 return(cur);
8129}
8130
8131/*
8132 * xmlXPathIsAncestor:
8133 * @ancestor: the ancestor node
8134 * @node: the current node
8135 *
8136 * Check that @ancestor is a @node's ancestor
8137 *
8138 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8139 */
8140static int
8141xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8142 if ((ancestor == NULL) || (node == NULL)) return(0);
8143 /* nodes need to be in the same document */
8144 if (ancestor->doc != node->doc) return(0);
8145 /* avoid searching if ancestor or node is the root node */
8146 if (ancestor == (xmlNodePtr) node->doc) return(1);
8147 if (node == (xmlNodePtr) ancestor->doc) return(0);
8148 while (node->parent != NULL) {
8149 if (node->parent == ancestor)
8150 return(1);
8151 node = node->parent;
8152 }
8153 return(0);
8154}
8155
8156/**
8157 * xmlXPathNextPreceding:
8158 * @ctxt: the XPath Parser context
8159 * @cur: the current node in the traversal
8160 *
8161 * Traversal function for the "preceding" direction
8162 * the preceding axis contains all nodes in the same document as the context
8163 * node that are before the context node in document order, excluding any
8164 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8165 * ordered in reverse document order
8166 *
8167 * Returns the next element following that axis
8168 */
8169xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00008170xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8171{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008172 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008173 if (cur == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008174 cur = ctxt->context->node;
Daniel Veillardea90b892010-10-22 15:50:50 +02008175 if (cur->type == XML_NAMESPACE_DECL)
8176 return(NULL);
8177 if (cur->type == XML_ATTRIBUTE_NODE)
8178 return(cur->parent);
8179 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00008180 if (cur == NULL)
8181 return (NULL);
8182 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8183 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00008184 do {
8185 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008186 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8187 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008188 }
8189
8190 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008191 if (cur == NULL)
8192 return (NULL);
8193 if (cur == ctxt->context->doc->children)
8194 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008195 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00008196 return (cur);
8197}
8198
8199/**
8200 * xmlXPathNextPrecedingInternal:
8201 * @ctxt: the XPath Parser context
8202 * @cur: the current node in the traversal
8203 *
8204 * Traversal function for the "preceding" direction
8205 * the preceding axis contains all nodes in the same document as the context
8206 * node that are before the context node in document order, excluding any
8207 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8208 * ordered in reverse document order
Daniel Veillard45490ae2008-07-29 09:13:19 +00008209 * This is a faster implementation but internal only since it requires a
Daniel Veillardf06307e2001-07-03 10:35:50 +00008210 * state kept in the parser context: ctxt->ancestor.
8211 *
8212 * Returns the next element following that axis
8213 */
8214static xmlNodePtr
8215xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8216 xmlNodePtr cur)
8217{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008218 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008219 if (cur == NULL) {
8220 cur = ctxt->context->node;
8221 if (cur == NULL)
8222 return (NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008223 if (cur->type == XML_NAMESPACE_DECL)
8224 return (NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008225 ctxt->ancestor = cur->parent;
8226 }
8227 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8228 cur = cur->prev;
8229 while (cur->prev == NULL) {
8230 cur = cur->parent;
8231 if (cur == NULL)
8232 return (NULL);
8233 if (cur == ctxt->context->doc->children)
8234 return (NULL);
8235 if (cur != ctxt->ancestor)
8236 return (cur);
8237 ctxt->ancestor = cur->parent;
8238 }
8239 cur = cur->prev;
8240 while (cur->last != NULL)
8241 cur = cur->last;
8242 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008243}
8244
8245/**
8246 * xmlXPathNextNamespace:
8247 * @ctxt: the XPath Parser context
8248 * @cur: the current attribute in the traversal
8249 *
8250 * Traversal function for the "namespace" direction
8251 * the namespace axis contains the namespace nodes of the context node;
8252 * the order of nodes on this axis is implementation-defined; the axis will
8253 * be empty unless the context node is an element
8254 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008255 * We keep the XML namespace node at the end of the list.
8256 *
Owen Taylor3473f882001-02-23 17:55:21 +00008257 * Returns the next element following that axis
8258 */
8259xmlNodePtr
8260xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008261 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008262 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00008263 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008264 if (ctxt->context->tmpNsList != NULL)
8265 xmlFree(ctxt->context->tmpNsList);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008266 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00008267 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008268 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00008269 if (ctxt->context->tmpNsList != NULL) {
8270 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8271 ctxt->context->tmpNsNr++;
8272 }
8273 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008274 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008275 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00008276 if (ctxt->context->tmpNsNr > 0) {
8277 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8278 } else {
8279 if (ctxt->context->tmpNsList != NULL)
8280 xmlFree(ctxt->context->tmpNsList);
8281 ctxt->context->tmpNsList = NULL;
8282 return(NULL);
8283 }
Owen Taylor3473f882001-02-23 17:55:21 +00008284}
8285
8286/**
8287 * xmlXPathNextAttribute:
8288 * @ctxt: the XPath Parser context
8289 * @cur: the current attribute in the traversal
8290 *
8291 * Traversal function for the "attribute" direction
8292 * TODO: support DTD inherited default attributes
8293 *
8294 * Returns the next element following that axis
8295 */
8296xmlNodePtr
8297xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008298 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00008299 if (ctxt->context->node == NULL)
8300 return(NULL);
8301 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8302 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008303 if (cur == NULL) {
8304 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8305 return(NULL);
8306 return((xmlNodePtr)ctxt->context->node->properties);
8307 }
8308 return((xmlNodePtr)cur->next);
8309}
8310
8311/************************************************************************
8312 * *
8313 * NodeTest Functions *
8314 * *
8315 ************************************************************************/
8316
Owen Taylor3473f882001-02-23 17:55:21 +00008317#define IS_FUNCTION 200
8318
Owen Taylor3473f882001-02-23 17:55:21 +00008319
8320/************************************************************************
8321 * *
8322 * Implicit tree core function library *
8323 * *
8324 ************************************************************************/
8325
8326/**
8327 * xmlXPathRoot:
8328 * @ctxt: the XPath Parser context
8329 *
8330 * Initialize the context to the root of the document
8331 */
8332void
8333xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008334 if ((ctxt == NULL) || (ctxt->context == NULL))
8335 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008336 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008337 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8338 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008339}
8340
8341/************************************************************************
8342 * *
8343 * The explicit core function library *
8344 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8345 * *
8346 ************************************************************************/
8347
8348
8349/**
8350 * xmlXPathLastFunction:
8351 * @ctxt: the XPath Parser context
8352 * @nargs: the number of arguments
8353 *
8354 * Implement the last() XPath function
8355 * number last()
8356 * The last function returns the number of nodes in the context node list.
8357 */
8358void
8359xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8360 CHECK_ARITY(0);
8361 if (ctxt->context->contextSize >= 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008362 valuePush(ctxt,
8363 xmlXPathCacheNewFloat(ctxt->context,
8364 (double) ctxt->context->contextSize));
Owen Taylor3473f882001-02-23 17:55:21 +00008365#ifdef DEBUG_EXPR
8366 xmlGenericError(xmlGenericErrorContext,
8367 "last() : %d\n", ctxt->context->contextSize);
8368#endif
8369 } else {
8370 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8371 }
8372}
8373
8374/**
8375 * xmlXPathPositionFunction:
8376 * @ctxt: the XPath Parser context
8377 * @nargs: the number of arguments
8378 *
8379 * Implement the position() XPath function
8380 * number position()
8381 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008382 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00008383 * will be equal to last().
8384 */
8385void
8386xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8387 CHECK_ARITY(0);
8388 if (ctxt->context->proximityPosition >= 0) {
8389 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008390 xmlXPathCacheNewFloat(ctxt->context,
8391 (double) ctxt->context->proximityPosition));
Owen Taylor3473f882001-02-23 17:55:21 +00008392#ifdef DEBUG_EXPR
8393 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8394 ctxt->context->proximityPosition);
8395#endif
8396 } else {
8397 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8398 }
8399}
8400
8401/**
8402 * xmlXPathCountFunction:
8403 * @ctxt: the XPath Parser context
8404 * @nargs: the number of arguments
8405 *
8406 * Implement the count() XPath function
8407 * number count(node-set)
8408 */
8409void
8410xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8411 xmlXPathObjectPtr cur;
8412
8413 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008414 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008415 ((ctxt->value->type != XPATH_NODESET) &&
8416 (ctxt->value->type != XPATH_XSLT_TREE)))
8417 XP_ERROR(XPATH_INVALID_TYPE);
8418 cur = valuePop(ctxt);
8419
Daniel Veillard911f49a2001-04-07 15:39:35 +00008420 if ((cur == NULL) || (cur->nodesetval == NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008421 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00008422 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008423 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8424 (double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00008425 } else {
8426 if ((cur->nodesetval->nodeNr != 1) ||
8427 (cur->nodesetval->nodeTab == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008428 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00008429 } else {
8430 xmlNodePtr tmp;
8431 int i = 0;
8432
8433 tmp = cur->nodesetval->nodeTab[0];
8434 if (tmp != NULL) {
8435 tmp = tmp->children;
8436 while (tmp != NULL) {
8437 tmp = tmp->next;
8438 i++;
8439 }
8440 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008441 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
Daniel Veillardfe703322001-08-14 12:18:09 +00008442 }
8443 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008444 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008445}
8446
8447/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008448 * xmlXPathGetElementsByIds:
8449 * @doc: the document
8450 * @ids: a whitespace separated list of IDs
8451 *
8452 * Selects elements by their unique ID.
8453 *
8454 * Returns a node-set of selected elements.
8455 */
8456static xmlNodeSetPtr
8457xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8458 xmlNodeSetPtr ret;
8459 const xmlChar *cur = ids;
8460 xmlChar *ID;
8461 xmlAttrPtr attr;
8462 xmlNodePtr elem = NULL;
8463
Daniel Veillard7a985a12003-07-06 17:57:42 +00008464 if (ids == NULL) return(NULL);
8465
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008466 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00008467 if (ret == NULL)
8468 return(ret);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008469
William M. Brack76e95df2003-10-18 16:20:14 +00008470 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008471 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008472 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00008473 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008474
8475 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00008476 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00008477 /*
8478 * We used to check the fact that the value passed
8479 * was an NCName, but this generated much troubles for
8480 * me and Aleksey Sanin, people blatantly violated that
8481 * constaint, like Visa3D spec.
8482 * if (xmlValidateNCName(ID, 1) == 0)
8483 */
8484 attr = xmlGetID(doc, ID);
8485 if (attr != NULL) {
8486 if (attr->type == XML_ATTRIBUTE_NODE)
8487 elem = attr->parent;
8488 else if (attr->type == XML_ELEMENT_NODE)
8489 elem = (xmlNodePtr) attr;
8490 else
8491 elem = NULL;
8492 if (elem != NULL)
8493 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00008494 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008495 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00008496 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008497
William M. Brack76e95df2003-10-18 16:20:14 +00008498 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008499 ids = cur;
8500 }
8501 return(ret);
8502}
8503
8504/**
Owen Taylor3473f882001-02-23 17:55:21 +00008505 * xmlXPathIdFunction:
8506 * @ctxt: the XPath Parser context
8507 * @nargs: the number of arguments
8508 *
8509 * Implement the id() XPath function
8510 * node-set id(object)
8511 * The id function selects elements by their unique ID
8512 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8513 * then the result is the union of the result of applying id to the
8514 * string value of each of the nodes in the argument node-set. When the
8515 * argument to id is of any other type, the argument is converted to a
8516 * string as if by a call to the string function; the string is split
8517 * into a whitespace-separated list of tokens (whitespace is any sequence
8518 * of characters matching the production S); the result is a node-set
8519 * containing the elements in the same document as the context node that
8520 * have a unique ID equal to any of the tokens in the list.
8521 */
8522void
8523xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008524 xmlChar *tokens;
8525 xmlNodeSetPtr ret;
8526 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00008527
8528 CHECK_ARITY(1);
8529 obj = valuePop(ctxt);
8530 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00008531 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008532 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00008533 int i;
8534
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008535 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00008536 /*
8537 * FIXME -- in an out-of-memory condition this will behave badly.
8538 * The solution is not clear -- we already popped an item from
8539 * ctxt, so the object is in a corrupt state.
8540 */
Owen Taylor3473f882001-02-23 17:55:21 +00008541
Daniel Veillard911f49a2001-04-07 15:39:35 +00008542 if (obj->nodesetval != NULL) {
8543 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008544 tokens =
8545 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8546 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8547 ret = xmlXPathNodeSetMerge(ret, ns);
8548 xmlXPathFreeNodeSet(ns);
8549 if (tokens != NULL)
8550 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00008551 }
Owen Taylor3473f882001-02-23 17:55:21 +00008552 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008553 xmlXPathReleaseObject(ctxt->context, obj);
8554 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00008555 return;
8556 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008557 obj = xmlXPathCacheConvertString(ctxt->context, obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008558 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008559 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008560 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00008561 return;
8562}
8563
8564/**
8565 * xmlXPathLocalNameFunction:
8566 * @ctxt: the XPath Parser context
8567 * @nargs: the number of arguments
8568 *
8569 * Implement the local-name() XPath function
8570 * string local-name(node-set?)
8571 * The local-name function returns a string containing the local part
8572 * of the name of the node in the argument node-set that is first in
8573 * document order. If the node-set is empty or the first node has no
8574 * name, an empty string is returned. If the argument is omitted it
8575 * defaults to the context node.
8576 */
8577void
8578xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8579 xmlXPathObjectPtr cur;
8580
Daniel Veillarda82b1822004-11-08 16:24:57 +00008581 if (ctxt == NULL) return;
8582
Owen Taylor3473f882001-02-23 17:55:21 +00008583 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008584 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8585 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008586 nargs = 1;
8587 }
8588
8589 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008590 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008591 ((ctxt->value->type != XPATH_NODESET) &&
8592 (ctxt->value->type != XPATH_XSLT_TREE)))
8593 XP_ERROR(XPATH_INVALID_TYPE);
8594 cur = valuePop(ctxt);
8595
Daniel Veillard911f49a2001-04-07 15:39:35 +00008596 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008597 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008598 } else {
8599 int i = 0; /* Should be first in document order !!!!! */
8600 switch (cur->nodesetval->nodeTab[i]->type) {
8601 case XML_ELEMENT_NODE:
8602 case XML_ATTRIBUTE_NODE:
8603 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008604 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008605 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008606 else
8607 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008608 xmlXPathCacheNewString(ctxt->context,
8609 cur->nodesetval->nodeTab[i]->name));
Owen Taylor3473f882001-02-23 17:55:21 +00008610 break;
8611 case XML_NAMESPACE_DECL:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008612 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008613 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8614 break;
8615 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008616 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008617 }
8618 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008619 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008620}
8621
8622/**
8623 * xmlXPathNamespaceURIFunction:
8624 * @ctxt: the XPath Parser context
8625 * @nargs: the number of arguments
8626 *
8627 * Implement the namespace-uri() XPath function
8628 * string namespace-uri(node-set?)
8629 * The namespace-uri function returns a string containing the
8630 * namespace URI of the expanded name of the node in the argument
8631 * node-set that is first in document order. If the node-set is empty,
8632 * the first node has no name, or the expanded name has no namespace
8633 * URI, an empty string is returned. If the argument is omitted it
8634 * defaults to the context node.
8635 */
8636void
8637xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8638 xmlXPathObjectPtr cur;
8639
Daniel Veillarda82b1822004-11-08 16:24:57 +00008640 if (ctxt == NULL) return;
8641
Owen Taylor3473f882001-02-23 17:55:21 +00008642 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008643 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8644 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008645 nargs = 1;
8646 }
8647 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008648 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008649 ((ctxt->value->type != XPATH_NODESET) &&
8650 (ctxt->value->type != XPATH_XSLT_TREE)))
8651 XP_ERROR(XPATH_INVALID_TYPE);
8652 cur = valuePop(ctxt);
8653
Daniel Veillard911f49a2001-04-07 15:39:35 +00008654 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008655 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008656 } else {
8657 int i = 0; /* Should be first in document order !!!!! */
8658 switch (cur->nodesetval->nodeTab[i]->type) {
8659 case XML_ELEMENT_NODE:
8660 case XML_ATTRIBUTE_NODE:
8661 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008662 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008663 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008664 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008665 cur->nodesetval->nodeTab[i]->ns->href));
8666 break;
8667 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008668 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008669 }
8670 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008671 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008672}
8673
8674/**
8675 * xmlXPathNameFunction:
8676 * @ctxt: the XPath Parser context
8677 * @nargs: the number of arguments
8678 *
8679 * Implement the name() XPath function
8680 * string name(node-set?)
8681 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008682 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00008683 * order. The QName must represent the name with respect to the namespace
8684 * declarations in effect on the node whose name is being represented.
8685 * Typically, this will be the form in which the name occurred in the XML
8686 * source. This need not be the case if there are namespace declarations
8687 * in effect on the node that associate multiple prefixes with the same
8688 * namespace. However, an implementation may include information about
8689 * the original prefix in its representation of nodes; in this case, an
8690 * implementation can ensure that the returned string is always the same
8691 * as the QName used in the XML source. If the argument it omitted it
8692 * defaults to the context node.
8693 * Libxml keep the original prefix so the "real qualified name" used is
8694 * returned.
8695 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008696static void
Daniel Veillard04383752001-07-08 14:27:15 +00008697xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8698{
Owen Taylor3473f882001-02-23 17:55:21 +00008699 xmlXPathObjectPtr cur;
8700
8701 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008702 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8703 ctxt->context->node));
Daniel Veillard04383752001-07-08 14:27:15 +00008704 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008705 }
8706
8707 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00008708 if ((ctxt->value == NULL) ||
8709 ((ctxt->value->type != XPATH_NODESET) &&
8710 (ctxt->value->type != XPATH_XSLT_TREE)))
8711 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00008712 cur = valuePop(ctxt);
8713
Daniel Veillard911f49a2001-04-07 15:39:35 +00008714 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008715 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008716 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00008717 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00008718
Daniel Veillard04383752001-07-08 14:27:15 +00008719 switch (cur->nodesetval->nodeTab[i]->type) {
8720 case XML_ELEMENT_NODE:
8721 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008722 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008723 valuePush(ctxt,
8724 xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008725 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8726 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008727 valuePush(ctxt,
8728 xmlXPathCacheNewString(ctxt->context,
8729 cur->nodesetval->nodeTab[i]->name));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008730 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00008731 xmlChar *fullname;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008732
Daniel Veillardc00cda82003-04-07 10:22:39 +00008733 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8734 cur->nodesetval->nodeTab[i]->ns->prefix,
8735 NULL, 0);
8736 if (fullname == cur->nodesetval->nodeTab[i]->name)
8737 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8738 if (fullname == NULL) {
8739 XP_ERROR(XPATH_MEMORY_ERROR);
8740 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008741 valuePush(ctxt, xmlXPathCacheWrapString(
8742 ctxt->context, fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00008743 }
8744 break;
8745 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008746 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8747 cur->nodesetval->nodeTab[i]));
Daniel Veillard04383752001-07-08 14:27:15 +00008748 xmlXPathLocalNameFunction(ctxt, 1);
8749 }
Owen Taylor3473f882001-02-23 17:55:21 +00008750 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008751 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008752}
8753
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008754
8755/**
Owen Taylor3473f882001-02-23 17:55:21 +00008756 * xmlXPathStringFunction:
8757 * @ctxt: the XPath Parser context
8758 * @nargs: the number of arguments
8759 *
8760 * Implement the string() XPath function
8761 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00008762 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00008763 * - A node-set is converted to a string by returning the value of
8764 * the node in the node-set that is first in document order.
8765 * If the node-set is empty, an empty string is returned.
8766 * - A number is converted to a string as follows
Daniel Veillard45490ae2008-07-29 09:13:19 +00008767 * + NaN is converted to the string NaN
8768 * + positive zero is converted to the string 0
8769 * + negative zero is converted to the string 0
8770 * + positive infinity is converted to the string Infinity
8771 * + negative infinity is converted to the string -Infinity
Owen Taylor3473f882001-02-23 17:55:21 +00008772 * + if the number is an integer, the number is represented in
8773 * decimal form as a Number with no decimal point and no leading
8774 * zeros, preceded by a minus sign (-) if the number is negative
8775 * + otherwise, the number is represented in decimal form as a
8776 * Number including a decimal point with at least one digit
8777 * before the decimal point and at least one digit after the
8778 * decimal point, preceded by a minus sign (-) if the number
8779 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008780 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00008781 * before the decimal point; beyond the one required digit
8782 * after the decimal point there must be as many, but only as
8783 * many, more digits as are needed to uniquely distinguish the
8784 * number from all other IEEE 754 numeric values.
8785 * - The boolean false value is converted to the string false.
8786 * The boolean true value is converted to the string true.
8787 *
8788 * If the argument is omitted, it defaults to a node-set with the
8789 * context node as its only member.
8790 */
8791void
8792xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8793 xmlXPathObjectPtr cur;
8794
Daniel Veillarda82b1822004-11-08 16:24:57 +00008795 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008796 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008797 valuePush(ctxt,
8798 xmlXPathCacheWrapString(ctxt->context,
8799 xmlXPathCastNodeToString(ctxt->context->node)));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008800 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008801 }
8802
8803 CHECK_ARITY(1);
8804 cur = valuePop(ctxt);
8805 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008806 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00008807}
8808
8809/**
8810 * xmlXPathStringLengthFunction:
8811 * @ctxt: the XPath Parser context
8812 * @nargs: the number of arguments
8813 *
8814 * Implement the string-length() XPath function
8815 * number string-length(string?)
8816 * The string-length returns the number of characters in the string
8817 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8818 * the context node converted to a string, in other words the value
8819 * of the context node.
8820 */
8821void
8822xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8823 xmlXPathObjectPtr cur;
8824
8825 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008826 if ((ctxt == NULL) || (ctxt->context == NULL))
8827 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008828 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008829 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008830 } else {
8831 xmlChar *content;
8832
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008833 content = xmlXPathCastNodeToString(ctxt->context->node);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008834 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8835 xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00008836 xmlFree(content);
8837 }
8838 return;
8839 }
8840 CHECK_ARITY(1);
8841 CAST_TO_STRING;
8842 CHECK_TYPE(XPATH_STRING);
8843 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008844 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
Daniel Veillard45490ae2008-07-29 09:13:19 +00008845 xmlUTF8Strlen(cur->stringval)));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008846 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008847}
8848
8849/**
8850 * xmlXPathConcatFunction:
8851 * @ctxt: the XPath Parser context
8852 * @nargs: the number of arguments
8853 *
8854 * Implement the concat() XPath function
8855 * string concat(string, string, string*)
8856 * The concat function returns the concatenation of its arguments.
8857 */
8858void
8859xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8860 xmlXPathObjectPtr cur, newobj;
8861 xmlChar *tmp;
8862
Daniel Veillarda82b1822004-11-08 16:24:57 +00008863 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008864 if (nargs < 2) {
8865 CHECK_ARITY(2);
8866 }
8867
8868 CAST_TO_STRING;
8869 cur = valuePop(ctxt);
8870 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008871 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008872 return;
8873 }
8874 nargs--;
8875
8876 while (nargs > 0) {
8877 CAST_TO_STRING;
8878 newobj = valuePop(ctxt);
8879 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008880 xmlXPathReleaseObject(ctxt->context, newobj);
8881 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008882 XP_ERROR(XPATH_INVALID_TYPE);
8883 }
8884 tmp = xmlStrcat(newobj->stringval, cur->stringval);
8885 newobj->stringval = cur->stringval;
8886 cur->stringval = tmp;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008887 xmlXPathReleaseObject(ctxt->context, newobj);
Owen Taylor3473f882001-02-23 17:55:21 +00008888 nargs--;
8889 }
8890 valuePush(ctxt, cur);
8891}
8892
8893/**
8894 * xmlXPathContainsFunction:
8895 * @ctxt: the XPath Parser context
8896 * @nargs: the number of arguments
8897 *
8898 * Implement the contains() XPath function
8899 * boolean contains(string, string)
8900 * The contains function returns true if the first argument string
8901 * contains the second argument string, and otherwise returns false.
8902 */
8903void
8904xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8905 xmlXPathObjectPtr hay, needle;
8906
8907 CHECK_ARITY(2);
8908 CAST_TO_STRING;
8909 CHECK_TYPE(XPATH_STRING);
8910 needle = valuePop(ctxt);
8911 CAST_TO_STRING;
8912 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008913
Owen Taylor3473f882001-02-23 17:55:21 +00008914 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008915 xmlXPathReleaseObject(ctxt->context, hay);
8916 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008917 XP_ERROR(XPATH_INVALID_TYPE);
8918 }
8919 if (xmlStrstr(hay->stringval, needle->stringval))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008920 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00008921 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008922 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8923 xmlXPathReleaseObject(ctxt->context, hay);
8924 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008925}
8926
8927/**
8928 * xmlXPathStartsWithFunction:
8929 * @ctxt: the XPath Parser context
8930 * @nargs: the number of arguments
8931 *
8932 * Implement the starts-with() XPath function
8933 * boolean starts-with(string, string)
8934 * The starts-with function returns true if the first argument string
8935 * starts with the second argument string, and otherwise returns false.
8936 */
8937void
8938xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8939 xmlXPathObjectPtr hay, needle;
8940 int n;
8941
8942 CHECK_ARITY(2);
8943 CAST_TO_STRING;
8944 CHECK_TYPE(XPATH_STRING);
8945 needle = valuePop(ctxt);
8946 CAST_TO_STRING;
8947 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008948
Owen Taylor3473f882001-02-23 17:55:21 +00008949 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008950 xmlXPathReleaseObject(ctxt->context, hay);
8951 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008952 XP_ERROR(XPATH_INVALID_TYPE);
8953 }
8954 n = xmlStrlen(needle->stringval);
8955 if (xmlStrncmp(hay->stringval, needle->stringval, n))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008956 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008957 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008958 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8959 xmlXPathReleaseObject(ctxt->context, hay);
8960 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008961}
8962
8963/**
8964 * xmlXPathSubstringFunction:
8965 * @ctxt: the XPath Parser context
8966 * @nargs: the number of arguments
8967 *
8968 * Implement the substring() XPath function
8969 * string substring(string, number, number?)
8970 * The substring function returns the substring of the first argument
8971 * starting at the position specified in the second argument with
8972 * length specified in the third argument. For example,
8973 * substring("12345",2,3) returns "234". If the third argument is not
8974 * specified, it returns the substring starting at the position specified
8975 * in the second argument and continuing to the end of the string. For
8976 * example, substring("12345",2) returns "2345". More precisely, each
8977 * character in the string (see [3.6 Strings]) is considered to have a
8978 * numeric position: the position of the first character is 1, the position
8979 * of the second character is 2 and so on. The returned substring contains
8980 * those characters for which the position of the character is greater than
8981 * or equal to the second argument and, if the third argument is specified,
8982 * less than the sum of the second and third arguments; the comparisons
8983 * and addition used for the above follow the standard IEEE 754 rules. Thus:
Daniel Veillard45490ae2008-07-29 09:13:19 +00008984 * - substring("12345", 1.5, 2.6) returns "234"
8985 * - substring("12345", 0, 3) returns "12"
8986 * - substring("12345", 0 div 0, 3) returns ""
8987 * - substring("12345", 1, 0 div 0) returns ""
8988 * - substring("12345", -42, 1 div 0) returns "12345"
8989 * - substring("12345", -1 div 0, 1 div 0) returns ""
Owen Taylor3473f882001-02-23 17:55:21 +00008990 */
8991void
8992xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8993 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00008994 double le=0, in;
8995 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00008996 xmlChar *ret;
8997
Owen Taylor3473f882001-02-23 17:55:21 +00008998 if (nargs < 2) {
8999 CHECK_ARITY(2);
9000 }
9001 if (nargs > 3) {
9002 CHECK_ARITY(3);
9003 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009004 /*
9005 * take care of possible last (position) argument
9006 */
Owen Taylor3473f882001-02-23 17:55:21 +00009007 if (nargs == 3) {
9008 CAST_TO_NUMBER;
9009 CHECK_TYPE(XPATH_NUMBER);
9010 len = valuePop(ctxt);
9011 le = len->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009012 xmlXPathReleaseObject(ctxt->context, len);
Owen Taylor3473f882001-02-23 17:55:21 +00009013 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009014
Owen Taylor3473f882001-02-23 17:55:21 +00009015 CAST_TO_NUMBER;
9016 CHECK_TYPE(XPATH_NUMBER);
9017 start = valuePop(ctxt);
9018 in = start->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009019 xmlXPathReleaseObject(ctxt->context, start);
Owen Taylor3473f882001-02-23 17:55:21 +00009020 CAST_TO_STRING;
9021 CHECK_TYPE(XPATH_STRING);
9022 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00009023 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00009024
Daniel Veillard97ac1312001-05-30 19:14:17 +00009025 /*
9026 * If last pos not present, calculate last position
9027 */
Daniel Veillard9e412302002-06-10 15:59:44 +00009028 if (nargs != 3) {
9029 le = (double)m;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009030 if (in < 1.0)
Daniel Veillard9e412302002-06-10 15:59:44 +00009031 in = 1.0;
9032 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009033
Daniel Veillard45490ae2008-07-29 09:13:19 +00009034 /* Need to check for the special cases where either
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009035 * the index is NaN, the length is NaN, or both
9036 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00009037 */
Daniel Veillard48b3eb22009-03-25 09:51:19 +00009038 if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009039 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00009040 * To meet the requirements of the spec, the arguments
Daniel Veillard45490ae2008-07-29 09:13:19 +00009041 * must be converted to integer format before
Daniel Veillard9e412302002-06-10 15:59:44 +00009042 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009043 *
Daniel Veillard9e412302002-06-10 15:59:44 +00009044 * First we go to integer form, rounding up
9045 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009046 */
9047 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00009048 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00009049
Daniel Veillard9e412302002-06-10 15:59:44 +00009050 if (xmlXPathIsInf(le) == 1) {
9051 l = m;
9052 if (i < 1)
9053 i = 1;
9054 }
9055 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9056 l = 0;
9057 else {
9058 l = (int) le;
9059 if (((double)l)+0.5 <= le) l++;
9060 }
9061
9062 /* Now we normalize inidices */
9063 i -= 1;
9064 l += i;
9065 if (i < 0)
9066 i = 0;
9067 if (l > m)
9068 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00009069
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009070 /* number of chars to copy */
9071 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00009072
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009073 ret = xmlUTF8Strsub(str->stringval, i, l);
9074 }
9075 else {
9076 ret = NULL;
9077 }
Owen Taylor3473f882001-02-23 17:55:21 +00009078 if (ret == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009079 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00009080 else {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009081 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009082 xmlFree(ret);
9083 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009084 xmlXPathReleaseObject(ctxt->context, str);
Owen Taylor3473f882001-02-23 17:55:21 +00009085}
9086
9087/**
9088 * xmlXPathSubstringBeforeFunction:
9089 * @ctxt: the XPath Parser context
9090 * @nargs: the number of arguments
9091 *
9092 * Implement the substring-before() XPath function
9093 * string substring-before(string, string)
9094 * The substring-before function returns the substring of the first
9095 * argument string that precedes the first occurrence of the second
9096 * argument string in the first argument string, or the empty string
9097 * if the first argument string does not contain the second argument
9098 * string. For example, substring-before("1999/04/01","/") returns 1999.
9099 */
9100void
9101xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9102 xmlXPathObjectPtr str;
9103 xmlXPathObjectPtr find;
9104 xmlBufferPtr target;
9105 const xmlChar *point;
9106 int offset;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009107
Owen Taylor3473f882001-02-23 17:55:21 +00009108 CHECK_ARITY(2);
9109 CAST_TO_STRING;
9110 find = valuePop(ctxt);
9111 CAST_TO_STRING;
9112 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009113
Owen Taylor3473f882001-02-23 17:55:21 +00009114 target = xmlBufferCreate();
9115 if (target) {
9116 point = xmlStrstr(str->stringval, find->stringval);
9117 if (point) {
9118 offset = (int)(point - str->stringval);
9119 xmlBufferAdd(target, str->stringval, offset);
9120 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009121 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9122 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00009123 xmlBufferFree(target);
9124 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009125 xmlXPathReleaseObject(ctxt->context, str);
9126 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009127}
9128
9129/**
9130 * xmlXPathSubstringAfterFunction:
9131 * @ctxt: the XPath Parser context
9132 * @nargs: the number of arguments
9133 *
9134 * Implement the substring-after() XPath function
9135 * string substring-after(string, string)
9136 * The substring-after function returns the substring of the first
9137 * argument string that follows the first occurrence of the second
9138 * argument string in the first argument string, or the empty stringi
9139 * if the first argument string does not contain the second argument
9140 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9141 * and substring-after("1999/04/01","19") returns 99/04/01.
9142 */
9143void
9144xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9145 xmlXPathObjectPtr str;
9146 xmlXPathObjectPtr find;
9147 xmlBufferPtr target;
9148 const xmlChar *point;
9149 int offset;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009150
Owen Taylor3473f882001-02-23 17:55:21 +00009151 CHECK_ARITY(2);
9152 CAST_TO_STRING;
9153 find = valuePop(ctxt);
9154 CAST_TO_STRING;
9155 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009156
Owen Taylor3473f882001-02-23 17:55:21 +00009157 target = xmlBufferCreate();
9158 if (target) {
9159 point = xmlStrstr(str->stringval, find->stringval);
9160 if (point) {
9161 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9162 xmlBufferAdd(target, &str->stringval[offset],
9163 xmlStrlen(str->stringval) - offset);
9164 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009165 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillard45490ae2008-07-29 09:13:19 +00009166 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00009167 xmlBufferFree(target);
9168 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009169 xmlXPathReleaseObject(ctxt->context, str);
9170 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009171}
9172
9173/**
9174 * xmlXPathNormalizeFunction:
9175 * @ctxt: the XPath Parser context
9176 * @nargs: the number of arguments
9177 *
9178 * Implement the normalize-space() XPath function
9179 * string normalize-space(string?)
9180 * The normalize-space function returns the argument string with white
9181 * space normalized by stripping leading and trailing whitespace
9182 * and replacing sequences of whitespace characters by a single
9183 * space. Whitespace characters are the same allowed by the S production
9184 * in XML. If the argument is omitted, it defaults to the context
9185 * node converted to a string, in other words the value of the context node.
9186 */
9187void
9188xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9189 xmlXPathObjectPtr obj = NULL;
9190 xmlChar *source = NULL;
9191 xmlBufferPtr target;
9192 xmlChar blank;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009193
Daniel Veillarda82b1822004-11-08 16:24:57 +00009194 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009195 if (nargs == 0) {
9196 /* Use current context node */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009197 valuePush(ctxt,
9198 xmlXPathCacheWrapString(ctxt->context,
9199 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00009200 nargs = 1;
9201 }
9202
9203 CHECK_ARITY(1);
9204 CAST_TO_STRING;
9205 CHECK_TYPE(XPATH_STRING);
9206 obj = valuePop(ctxt);
9207 source = obj->stringval;
9208
9209 target = xmlBufferCreate();
9210 if (target && source) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00009211
Owen Taylor3473f882001-02-23 17:55:21 +00009212 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00009213 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00009214 source++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009215
Owen Taylor3473f882001-02-23 17:55:21 +00009216 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9217 blank = 0;
9218 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00009219 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009220 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00009221 } else {
9222 if (blank) {
9223 xmlBufferAdd(target, &blank, 1);
9224 blank = 0;
9225 }
9226 xmlBufferAdd(target, source, 1);
9227 }
9228 source++;
9229 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009230 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9231 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00009232 xmlBufferFree(target);
9233 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009234 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00009235}
9236
9237/**
9238 * xmlXPathTranslateFunction:
9239 * @ctxt: the XPath Parser context
9240 * @nargs: the number of arguments
9241 *
9242 * Implement the translate() XPath function
9243 * string translate(string, string, string)
9244 * The translate function returns the first argument string with
9245 * occurrences of characters in the second argument string replaced
9246 * by the character at the corresponding position in the third argument
9247 * string. For example, translate("bar","abc","ABC") returns the string
9248 * BAr. If there is a character in the second argument string with no
9249 * character at a corresponding position in the third argument string
9250 * (because the second argument string is longer than the third argument
9251 * string), then occurrences of that character in the first argument
9252 * string are removed. For example, translate("--aaa--","abc-","ABC")
9253 * returns "AAA". If a character occurs more than once in second
9254 * argument string, then the first occurrence determines the replacement
9255 * character. If the third argument string is longer than the second
9256 * argument string, then excess characters are ignored.
9257 */
9258void
9259xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00009260 xmlXPathObjectPtr str;
9261 xmlXPathObjectPtr from;
9262 xmlXPathObjectPtr to;
9263 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009264 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009265 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00009266 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009267 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00009268
Daniel Veillarde043ee12001-04-16 14:08:07 +00009269 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00009270
Daniel Veillarde043ee12001-04-16 14:08:07 +00009271 CAST_TO_STRING;
9272 to = valuePop(ctxt);
9273 CAST_TO_STRING;
9274 from = valuePop(ctxt);
9275 CAST_TO_STRING;
9276 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009277
Daniel Veillarde043ee12001-04-16 14:08:07 +00009278 target = xmlBufferCreate();
9279 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009280 max = xmlUTF8Strlen(to->stringval);
9281 for (cptr = str->stringval; (ch=*cptr); ) {
9282 offset = xmlUTF8Strloc(from->stringval, cptr);
9283 if (offset >= 0) {
9284 if (offset < max) {
9285 point = xmlUTF8Strpos(to->stringval, offset);
9286 if (point)
9287 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
9288 }
9289 } else
9290 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9291
9292 /* Step to next character in input */
9293 cptr++;
9294 if ( ch & 0x80 ) {
9295 /* if not simple ascii, verify proper format */
9296 if ( (ch & 0xc0) != 0xc0 ) {
9297 xmlGenericError(xmlGenericErrorContext,
9298 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9299 break;
9300 }
9301 /* then skip over remaining bytes for this char */
9302 while ( (ch <<= 1) & 0x80 )
9303 if ( (*cptr++ & 0xc0) != 0x80 ) {
9304 xmlGenericError(xmlGenericErrorContext,
9305 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9306 break;
9307 }
9308 if (ch & 0x80) /* must have had error encountered */
9309 break;
9310 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00009311 }
Owen Taylor3473f882001-02-23 17:55:21 +00009312 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009313 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9314 xmlBufferContent(target)));
Daniel Veillarde043ee12001-04-16 14:08:07 +00009315 xmlBufferFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009316 xmlXPathReleaseObject(ctxt->context, str);
9317 xmlXPathReleaseObject(ctxt->context, from);
9318 xmlXPathReleaseObject(ctxt->context, to);
Owen Taylor3473f882001-02-23 17:55:21 +00009319}
9320
9321/**
9322 * xmlXPathBooleanFunction:
9323 * @ctxt: the XPath Parser context
9324 * @nargs: the number of arguments
9325 *
9326 * Implement the boolean() XPath function
9327 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00009328 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00009329 * - a number is true if and only if it is neither positive or
9330 * negative zero nor NaN
9331 * - a node-set is true if and only if it is non-empty
9332 * - a string is true if and only if its length is non-zero
9333 */
9334void
9335xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9336 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00009337
9338 CHECK_ARITY(1);
9339 cur = valuePop(ctxt);
9340 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009341 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009342 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009343}
9344
9345/**
9346 * xmlXPathNotFunction:
9347 * @ctxt: the XPath Parser context
9348 * @nargs: the number of arguments
9349 *
9350 * Implement the not() XPath function
9351 * boolean not(boolean)
9352 * The not function returns true if its argument is false,
9353 * and false otherwise.
9354 */
9355void
9356xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9357 CHECK_ARITY(1);
9358 CAST_TO_BOOLEAN;
9359 CHECK_TYPE(XPATH_BOOLEAN);
9360 ctxt->value->boolval = ! ctxt->value->boolval;
9361}
9362
9363/**
9364 * xmlXPathTrueFunction:
9365 * @ctxt: the XPath Parser context
9366 * @nargs: the number of arguments
9367 *
9368 * Implement the true() XPath function
9369 * boolean true()
9370 */
9371void
9372xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9373 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009374 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009375}
9376
9377/**
9378 * xmlXPathFalseFunction:
9379 * @ctxt: the XPath Parser context
9380 * @nargs: the number of arguments
9381 *
9382 * Implement the false() XPath function
9383 * boolean false()
9384 */
9385void
9386xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9387 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009388 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009389}
9390
9391/**
9392 * xmlXPathLangFunction:
9393 * @ctxt: the XPath Parser context
9394 * @nargs: the number of arguments
9395 *
9396 * Implement the lang() XPath function
9397 * boolean lang(string)
9398 * The lang function returns true or false depending on whether the
9399 * language of the context node as specified by xml:lang attributes
9400 * is the same as or is a sublanguage of the language specified by
9401 * the argument string. The language of the context node is determined
9402 * by the value of the xml:lang attribute on the context node, or, if
9403 * the context node has no xml:lang attribute, by the value of the
9404 * xml:lang attribute on the nearest ancestor of the context node that
9405 * has an xml:lang attribute. If there is no such attribute, then lang
9406 * returns false. If there is such an attribute, then lang returns
9407 * true if the attribute value is equal to the argument ignoring case,
9408 * or if there is some suffix starting with - such that the attribute
9409 * value is equal to the argument ignoring that suffix of the attribute
9410 * value and ignoring case.
9411 */
9412void
9413xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009414 xmlXPathObjectPtr val = NULL;
9415 const xmlChar *theLang = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009416 const xmlChar *lang;
9417 int ret = 0;
9418 int i;
9419
9420 CHECK_ARITY(1);
9421 CAST_TO_STRING;
9422 CHECK_TYPE(XPATH_STRING);
9423 val = valuePop(ctxt);
9424 lang = val->stringval;
9425 theLang = xmlNodeGetLang(ctxt->context->node);
9426 if ((theLang != NULL) && (lang != NULL)) {
9427 for (i = 0;lang[i] != 0;i++)
9428 if (toupper(lang[i]) != toupper(theLang[i]))
9429 goto not_equal;
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009430 if ((theLang[i] == 0) || (theLang[i] == '-'))
9431 ret = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009432 }
9433not_equal:
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009434 if (theLang != NULL)
9435 xmlFree((void *)theLang);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009436
9437 xmlXPathReleaseObject(ctxt->context, val);
9438 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009439}
9440
9441/**
9442 * xmlXPathNumberFunction:
9443 * @ctxt: the XPath Parser context
9444 * @nargs: the number of arguments
9445 *
9446 * Implement the number() XPath function
9447 * number number(object?)
9448 */
9449void
9450xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9451 xmlXPathObjectPtr cur;
9452 double res;
9453
Daniel Veillarda82b1822004-11-08 16:24:57 +00009454 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009455 if (nargs == 0) {
9456 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009457 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
Owen Taylor3473f882001-02-23 17:55:21 +00009458 } else {
9459 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9460
9461 res = xmlXPathStringEvalNumber(content);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009462 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
Owen Taylor3473f882001-02-23 17:55:21 +00009463 xmlFree(content);
9464 }
9465 return;
9466 }
9467
9468 CHECK_ARITY(1);
9469 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009470 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00009471}
9472
9473/**
9474 * xmlXPathSumFunction:
9475 * @ctxt: the XPath Parser context
9476 * @nargs: the number of arguments
9477 *
9478 * Implement the sum() XPath function
9479 * number sum(node-set)
9480 * The sum function returns the sum of the values of the nodes in
9481 * the argument node-set.
9482 */
9483void
9484xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9485 xmlXPathObjectPtr cur;
9486 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009487 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00009488
9489 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009490 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009491 ((ctxt->value->type != XPATH_NODESET) &&
9492 (ctxt->value->type != XPATH_XSLT_TREE)))
9493 XP_ERROR(XPATH_INVALID_TYPE);
9494 cur = valuePop(ctxt);
9495
William M. Brack08171912003-12-29 02:52:11 +00009496 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009497 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9498 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00009499 }
9500 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009501 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9502 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009503}
9504
William M. Brack3d426662005-04-19 14:40:28 +00009505/*
9506 * To assure working code on multiple platforms, we want to only depend
9507 * upon the characteristic truncation of converting a floating point value
9508 * to an integer. Unfortunately, because of the different storage sizes
9509 * of our internal floating point value (double) and integer (int), we
9510 * can't directly convert (see bug 301162). This macro is a messy
9511 * 'workaround'
9512 */
9513#define XTRUNC(f, v) \
9514 f = fmod((v), INT_MAX); \
9515 f = (v) - (f) + (double)((int)(f));
9516
Owen Taylor3473f882001-02-23 17:55:21 +00009517/**
9518 * xmlXPathFloorFunction:
9519 * @ctxt: the XPath Parser context
9520 * @nargs: the number of arguments
9521 *
9522 * Implement the floor() XPath function
9523 * number floor(number)
9524 * The floor function returns the largest (closest to positive infinity)
9525 * number that is not greater than the argument and that is an integer.
9526 */
9527void
9528xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009529 double f;
9530
Owen Taylor3473f882001-02-23 17:55:21 +00009531 CHECK_ARITY(1);
9532 CAST_TO_NUMBER;
9533 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009534
William M. Brack3d426662005-04-19 14:40:28 +00009535 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009536 if (f != ctxt->value->floatval) {
9537 if (ctxt->value->floatval > 0)
9538 ctxt->value->floatval = f;
9539 else
9540 ctxt->value->floatval = f - 1;
9541 }
Owen Taylor3473f882001-02-23 17:55:21 +00009542}
9543
9544/**
9545 * xmlXPathCeilingFunction:
9546 * @ctxt: the XPath Parser context
9547 * @nargs: the number of arguments
9548 *
9549 * Implement the ceiling() XPath function
9550 * number ceiling(number)
9551 * The ceiling function returns the smallest (closest to negative infinity)
9552 * number that is not less than the argument and that is an integer.
9553 */
9554void
9555xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9556 double f;
9557
9558 CHECK_ARITY(1);
9559 CAST_TO_NUMBER;
9560 CHECK_TYPE(XPATH_NUMBER);
9561
9562#if 0
9563 ctxt->value->floatval = ceil(ctxt->value->floatval);
9564#else
William M. Brack3d426662005-04-19 14:40:28 +00009565 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009566 if (f != ctxt->value->floatval) {
9567 if (ctxt->value->floatval > 0)
9568 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009569 else {
9570 if (ctxt->value->floatval < 0 && f == 0)
9571 ctxt->value->floatval = xmlXPathNZERO;
9572 else
9573 ctxt->value->floatval = f;
9574 }
9575
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009576 }
Owen Taylor3473f882001-02-23 17:55:21 +00009577#endif
9578}
9579
9580/**
9581 * xmlXPathRoundFunction:
9582 * @ctxt: the XPath Parser context
9583 * @nargs: the number of arguments
9584 *
9585 * Implement the round() XPath function
9586 * number round(number)
9587 * The round function returns the number that is closest to the
9588 * argument and that is an integer. If there are two such numbers,
9589 * then the one that is even is returned.
9590 */
9591void
9592xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9593 double f;
9594
9595 CHECK_ARITY(1);
9596 CAST_TO_NUMBER;
9597 CHECK_TYPE(XPATH_NUMBER);
9598
Daniel Veillardcda96922001-08-21 10:56:31 +00009599 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9600 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9601 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009602 (ctxt->value->floatval == 0.0))
9603 return;
9604
William M. Brack3d426662005-04-19 14:40:28 +00009605 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009606 if (ctxt->value->floatval < 0) {
9607 if (ctxt->value->floatval < f - 0.5)
9608 ctxt->value->floatval = f - 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009609 else
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009610 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009611 if (ctxt->value->floatval == 0)
9612 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009613 } else {
9614 if (ctxt->value->floatval < f + 0.5)
9615 ctxt->value->floatval = f;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009616 else
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009617 ctxt->value->floatval = f + 1;
9618 }
Owen Taylor3473f882001-02-23 17:55:21 +00009619}
9620
9621/************************************************************************
9622 * *
9623 * The Parser *
9624 * *
9625 ************************************************************************/
9626
9627/*
William M. Brack08171912003-12-29 02:52:11 +00009628 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00009629 * implementation.
9630 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009631static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009632static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009633static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009634static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00009635static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9636 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00009637
9638/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00009639 * xmlXPathCurrentChar:
9640 * @ctxt: the XPath parser context
9641 * @cur: pointer to the beginning of the char
9642 * @len: pointer to the length of the char read
9643 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009644 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00009645 * bytes in the input buffer.
9646 *
Daniel Veillard60087f32001-10-10 09:45:09 +00009647 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00009648 */
9649
9650static int
9651xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9652 unsigned char c;
9653 unsigned int val;
9654 const xmlChar *cur;
9655
9656 if (ctxt == NULL)
9657 return(0);
9658 cur = ctxt->cur;
9659
9660 /*
9661 * We are supposed to handle UTF8, check it's valid
9662 * From rfc2044: encoding of the Unicode values on UTF-8:
9663 *
9664 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9665 * 0000 0000-0000 007F 0xxxxxxx
9666 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
Daniel Veillard45490ae2008-07-29 09:13:19 +00009667 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
Daniel Veillard61d80a22001-04-27 17:13:01 +00009668 *
9669 * Check for the 0x110000 limit too
9670 */
9671 c = *cur;
9672 if (c & 0x80) {
9673 if ((cur[1] & 0xc0) != 0x80)
9674 goto encoding_error;
9675 if ((c & 0xe0) == 0xe0) {
9676
9677 if ((cur[2] & 0xc0) != 0x80)
9678 goto encoding_error;
9679 if ((c & 0xf0) == 0xf0) {
9680 if (((c & 0xf8) != 0xf0) ||
9681 ((cur[3] & 0xc0) != 0x80))
9682 goto encoding_error;
9683 /* 4-byte code */
9684 *len = 4;
9685 val = (cur[0] & 0x7) << 18;
9686 val |= (cur[1] & 0x3f) << 12;
9687 val |= (cur[2] & 0x3f) << 6;
9688 val |= cur[3] & 0x3f;
9689 } else {
9690 /* 3-byte code */
9691 *len = 3;
9692 val = (cur[0] & 0xf) << 12;
9693 val |= (cur[1] & 0x3f) << 6;
9694 val |= cur[2] & 0x3f;
9695 }
9696 } else {
9697 /* 2-byte code */
9698 *len = 2;
9699 val = (cur[0] & 0x1f) << 6;
9700 val |= cur[1] & 0x3f;
9701 }
9702 if (!IS_CHAR(val)) {
9703 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009704 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00009705 return(val);
9706 } else {
9707 /* 1-byte code */
9708 *len = 1;
9709 return((int) *cur);
9710 }
9711encoding_error:
9712 /*
William M. Brack08171912003-12-29 02:52:11 +00009713 * If we detect an UTF8 error that probably means that the
9714 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00009715 * declaration header. Report the error and switch the encoding
9716 * to ISO-Latin-1 (if you don't like this policy, just declare the
9717 * encoding !)
9718 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00009719 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00009720 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009721}
9722
9723/**
Owen Taylor3473f882001-02-23 17:55:21 +00009724 * xmlXPathParseNCName:
9725 * @ctxt: the XPath Parser context
9726 *
9727 * parse an XML namespace non qualified name.
9728 *
9729 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9730 *
9731 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9732 * CombiningChar | Extender
9733 *
9734 * Returns the namespace name or NULL
9735 */
9736
9737xmlChar *
9738xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00009739 const xmlChar *in;
9740 xmlChar *ret;
9741 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009742
Daniel Veillarda82b1822004-11-08 16:24:57 +00009743 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00009744 /*
9745 * Accelerator for simple ASCII names
9746 */
9747 in = ctxt->cur;
9748 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9749 ((*in >= 0x41) && (*in <= 0x5A)) ||
9750 (*in == '_')) {
9751 in++;
9752 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9753 ((*in >= 0x41) && (*in <= 0x5A)) ||
9754 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00009755 (*in == '_') || (*in == '.') ||
9756 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00009757 in++;
9758 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9759 (*in == '[') || (*in == ']') || (*in == ':') ||
9760 (*in == '@') || (*in == '*')) {
9761 count = in - ctxt->cur;
9762 if (count == 0)
9763 return(NULL);
9764 ret = xmlStrndup(ctxt->cur, count);
9765 ctxt->cur = in;
9766 return(ret);
9767 }
9768 }
9769 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009770}
9771
Daniel Veillard2156a562001-04-28 12:24:34 +00009772
Owen Taylor3473f882001-02-23 17:55:21 +00009773/**
9774 * xmlXPathParseQName:
9775 * @ctxt: the XPath Parser context
Daniel Veillard45490ae2008-07-29 09:13:19 +00009776 * @prefix: a xmlChar **
Owen Taylor3473f882001-02-23 17:55:21 +00009777 *
9778 * parse an XML qualified name
9779 *
9780 * [NS 5] QName ::= (Prefix ':')? LocalPart
9781 *
9782 * [NS 6] Prefix ::= NCName
9783 *
9784 * [NS 7] LocalPart ::= NCName
9785 *
9786 * Returns the function returns the local part, and prefix is updated
9787 * to get the Prefix if any.
9788 */
9789
Daniel Veillard56a4cb82001-03-24 17:00:36 +00009790static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00009791xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9792 xmlChar *ret = NULL;
9793
9794 *prefix = NULL;
9795 ret = xmlXPathParseNCName(ctxt);
Daniel Veillard074f37e2008-09-01 13:38:22 +00009796 if (ret && CUR == ':') {
Owen Taylor3473f882001-02-23 17:55:21 +00009797 *prefix = ret;
9798 NEXT;
9799 ret = xmlXPathParseNCName(ctxt);
9800 }
9801 return(ret);
9802}
9803
9804/**
9805 * xmlXPathParseName:
9806 * @ctxt: the XPath Parser context
9807 *
9808 * parse an XML name
9809 *
9810 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9811 * CombiningChar | Extender
9812 *
9813 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9814 *
9815 * Returns the namespace name or NULL
9816 */
9817
9818xmlChar *
9819xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009820 const xmlChar *in;
9821 xmlChar *ret;
9822 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009823
Daniel Veillarda82b1822004-11-08 16:24:57 +00009824 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009825 /*
9826 * Accelerator for simple ASCII names
9827 */
9828 in = ctxt->cur;
9829 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9830 ((*in >= 0x41) && (*in <= 0x5A)) ||
9831 (*in == '_') || (*in == ':')) {
9832 in++;
9833 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9834 ((*in >= 0x41) && (*in <= 0x5A)) ||
9835 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00009836 (*in == '_') || (*in == '-') ||
9837 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00009838 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00009839 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009840 count = in - ctxt->cur;
9841 ret = xmlStrndup(ctxt->cur, count);
9842 ctxt->cur = in;
9843 return(ret);
9844 }
9845 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009846 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009847}
9848
Daniel Veillard61d80a22001-04-27 17:13:01 +00009849static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00009850xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009851 xmlChar buf[XML_MAX_NAMELEN + 5];
9852 int len = 0, l;
9853 int c;
9854
9855 /*
9856 * Handler for more complex cases
9857 */
9858 c = CUR_CHAR(l);
9859 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00009860 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9861 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00009862 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00009863 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009864 return(NULL);
9865 }
9866
9867 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9868 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9869 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00009870 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009871 (IS_COMBINING(c)) ||
9872 (IS_EXTENDER(c)))) {
9873 COPY_BUF(l,buf,len,c);
9874 NEXTL(l);
9875 c = CUR_CHAR(l);
9876 if (len >= XML_MAX_NAMELEN) {
9877 /*
9878 * Okay someone managed to make a huge name, so he's ready to pay
9879 * for the processing speed.
9880 */
9881 xmlChar *buffer;
9882 int max = len * 2;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009883
Daniel Veillard3c908dc2003-04-19 00:07:51 +00009884 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009885 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009886 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009887 }
9888 memcpy(buffer, buf, len);
9889 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9890 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00009891 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009892 (IS_COMBINING(c)) ||
9893 (IS_EXTENDER(c))) {
9894 if (len + 10 > max) {
9895 max *= 2;
9896 buffer = (xmlChar *) xmlRealloc(buffer,
9897 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009898 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009899 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009900 }
9901 }
9902 COPY_BUF(l,buffer,len,c);
9903 NEXTL(l);
9904 c = CUR_CHAR(l);
9905 }
9906 buffer[len] = 0;
9907 return(buffer);
9908 }
9909 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009910 if (len == 0)
9911 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009912 return(xmlStrndup(buf, len));
9913}
Daniel Veillard3cd72402002-05-13 10:33:30 +00009914
9915#define MAX_FRAC 20
9916
William M. Brack372a4452004-02-17 13:09:23 +00009917/*
9918 * These are used as divisors for the fractional part of a number.
9919 * Since the table includes 1.0 (representing '0' fractional digits),
9920 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
9921 */
9922static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +00009923 1.0, 10.0, 100.0, 1000.0, 10000.0,
9924 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
9925 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
9926 100000000000000.0,
9927 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +00009928 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +00009929};
9930
Owen Taylor3473f882001-02-23 17:55:21 +00009931/**
9932 * xmlXPathStringEvalNumber:
9933 * @str: A string to scan
9934 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00009935 * [30a] Float ::= Number ('e' Digits?)?
9936 *
Owen Taylor3473f882001-02-23 17:55:21 +00009937 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard45490ae2008-07-29 09:13:19 +00009938 * | '.' Digits
Owen Taylor3473f882001-02-23 17:55:21 +00009939 * [31] Digits ::= [0-9]+
9940 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009941 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00009942 * In complement of the Number expression, this function also handles
9943 * negative values : '-' Number.
9944 *
9945 * Returns the double value.
9946 */
9947double
9948xmlXPathStringEvalNumber(const xmlChar *str) {
9949 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00009950 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009951 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009952 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009953 int exponent = 0;
9954 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009955#ifdef __GNUC__
9956 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00009957 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009958#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00009959 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00009960 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009961 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
9962 return(xmlXPathNAN);
9963 }
9964 if (*cur == '-') {
9965 isneg = 1;
9966 cur++;
9967 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00009968
9969#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009970 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00009971 * tmp/temp is a workaround against a gcc compiler bug
9972 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009973 */
Daniel Veillard7b416132002-03-07 08:36:03 +00009974 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009975 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00009976 ret = ret * 10;
9977 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00009978 ok = 1;
9979 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00009980 temp = (double) tmp;
9981 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00009982 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00009983#else
Daniel Veillard7b416132002-03-07 08:36:03 +00009984 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009985 while ((*cur >= '0') && (*cur <= '9')) {
9986 ret = ret * 10 + (*cur - '0');
9987 ok = 1;
9988 cur++;
9989 }
9990#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009991
Owen Taylor3473f882001-02-23 17:55:21 +00009992 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00009993 int v, frac = 0;
9994 double fraction = 0;
9995
Owen Taylor3473f882001-02-23 17:55:21 +00009996 cur++;
9997 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
9998 return(xmlXPathNAN);
9999 }
Daniel Veillard3cd72402002-05-13 10:33:30 +000010000 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
10001 v = (*cur - '0');
10002 fraction = fraction * 10 + v;
10003 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010004 cur++;
10005 }
Daniel Veillard3cd72402002-05-13 10:33:30 +000010006 fraction /= my_pow10[frac];
10007 ret = ret + fraction;
10008 while ((*cur >= '0') && (*cur <= '9'))
10009 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010010 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010011 if ((*cur == 'e') || (*cur == 'E')) {
10012 cur++;
10013 if (*cur == '-') {
10014 is_exponent_negative = 1;
10015 cur++;
William M. Brack99127052004-05-24 02:52:28 +000010016 } else if (*cur == '+') {
10017 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010018 }
10019 while ((*cur >= '0') && (*cur <= '9')) {
10020 exponent = exponent * 10 + (*cur - '0');
10021 cur++;
10022 }
10023 }
William M. Brack76e95df2003-10-18 16:20:14 +000010024 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010025 if (*cur != 0) return(xmlXPathNAN);
10026 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010027 if (is_exponent_negative) exponent = -exponent;
10028 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +000010029 return(ret);
10030}
10031
10032/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010033 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +000010034 * @ctxt: the XPath Parser context
10035 *
10036 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard45490ae2008-07-29 09:13:19 +000010037 * | '.' Digits
Owen Taylor3473f882001-02-23 17:55:21 +000010038 * [31] Digits ::= [0-9]+
10039 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010040 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +000010041 *
10042 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010043static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010044xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10045{
Owen Taylor3473f882001-02-23 17:55:21 +000010046 double ret = 0.0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010047 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010048 int exponent = 0;
10049 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010050#ifdef __GNUC__
10051 unsigned long tmp = 0;
10052 double temp;
10053#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010054
10055 CHECK_ERROR;
10056 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10057 XP_ERROR(XPATH_NUMBER_ERROR);
10058 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010059#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010060 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010061 * tmp/temp is a workaround against a gcc compiler bug
10062 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010063 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010064 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010065 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010066 ret = ret * 10;
10067 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010068 ok = 1;
10069 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +000010070 temp = (double) tmp;
10071 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010072 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010073#else
10074 ret = 0;
10075 while ((CUR >= '0') && (CUR <= '9')) {
10076 ret = ret * 10 + (CUR - '0');
10077 ok = 1;
10078 NEXT;
10079 }
10080#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010081 if (CUR == '.') {
Phil Shaferee32ad32010-11-03 20:53:55 +010010082 int v, frac = 0;
10083 double fraction = 0;
10084
Owen Taylor3473f882001-02-23 17:55:21 +000010085 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010086 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10087 XP_ERROR(XPATH_NUMBER_ERROR);
10088 }
Phil Shaferee32ad32010-11-03 20:53:55 +010010089 while ((CUR >= '0') && (CUR <= '9') && (frac < MAX_FRAC)) {
10090 v = (CUR - '0');
10091 fraction = fraction * 10 + v;
10092 frac = frac + 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010093 NEXT;
10094 }
Phil Shaferee32ad32010-11-03 20:53:55 +010010095 fraction /= my_pow10[frac];
10096 ret = ret + fraction;
10097 while ((CUR >= '0') && (CUR <= '9'))
10098 NEXT;
Owen Taylor3473f882001-02-23 17:55:21 +000010099 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010100 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010101 NEXT;
10102 if (CUR == '-') {
10103 is_exponent_negative = 1;
10104 NEXT;
William M. Brack99127052004-05-24 02:52:28 +000010105 } else if (CUR == '+') {
10106 NEXT;
10107 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010108 while ((CUR >= '0') && (CUR <= '9')) {
10109 exponent = exponent * 10 + (CUR - '0');
10110 NEXT;
10111 }
10112 if (is_exponent_negative)
10113 exponent = -exponent;
10114 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +000010115 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010116 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010117 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010118}
10119
10120/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010121 * xmlXPathParseLiteral:
10122 * @ctxt: the XPath Parser context
10123 *
10124 * Parse a Literal
10125 *
10126 * [29] Literal ::= '"' [^"]* '"'
10127 * | "'" [^']* "'"
10128 *
10129 * Returns the value found or NULL in case of error
10130 */
10131static xmlChar *
10132xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10133 const xmlChar *q;
10134 xmlChar *ret = NULL;
10135
10136 if (CUR == '"') {
10137 NEXT;
10138 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010139 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010140 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010141 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010142 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010143 } else {
10144 ret = xmlStrndup(q, CUR_PTR - q);
10145 NEXT;
10146 }
10147 } else if (CUR == '\'') {
10148 NEXT;
10149 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010150 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010151 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010152 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010153 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010154 } else {
10155 ret = xmlStrndup(q, CUR_PTR - q);
10156 NEXT;
10157 }
10158 } else {
Daniel Veillard24505b02005-07-28 23:49:35 +000010159 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010160 }
10161 return(ret);
10162}
10163
10164/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010165 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +000010166 * @ctxt: the XPath Parser context
10167 *
10168 * Parse a Literal and push it on the stack.
10169 *
10170 * [29] Literal ::= '"' [^"]* '"'
10171 * | "'" [^']* "'"
10172 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010173 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +000010174 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010175static void
10176xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010177 const xmlChar *q;
10178 xmlChar *ret = NULL;
10179
10180 if (CUR == '"') {
10181 NEXT;
10182 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010183 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +000010184 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010185 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010186 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10187 } else {
10188 ret = xmlStrndup(q, CUR_PTR - q);
10189 NEXT;
10190 }
10191 } else if (CUR == '\'') {
10192 NEXT;
10193 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010194 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +000010195 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010196 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010197 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10198 } else {
10199 ret = xmlStrndup(q, CUR_PTR - q);
10200 NEXT;
10201 }
10202 } else {
10203 XP_ERROR(XPATH_START_LITERAL_ERROR);
10204 }
10205 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010206 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010207 xmlXPathCacheNewString(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010208 xmlFree(ret);
10209}
10210
10211/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010212 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +000010213 * @ctxt: the XPath Parser context
10214 *
10215 * Parse a VariableReference, evaluate it and push it on the stack.
10216 *
10217 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +000010218 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +000010219 * of any of the types that are possible for the value of an expression,
10220 * and may also be of additional types not specified here.
10221 *
10222 * Early evaluation is possible since:
10223 * The variable bindings [...] used to evaluate a subexpression are
Daniel Veillard45490ae2008-07-29 09:13:19 +000010224 * always the same as those used to evaluate the containing expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010225 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010226 * [36] VariableReference ::= '$' QName
Owen Taylor3473f882001-02-23 17:55:21 +000010227 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010228static void
10229xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010230 xmlChar *name;
10231 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010232
10233 SKIP_BLANKS;
10234 if (CUR != '$') {
10235 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10236 }
10237 NEXT;
10238 name = xmlXPathParseQName(ctxt, &prefix);
10239 if (name == NULL) {
10240 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10241 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010242 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010243 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10244 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010245 SKIP_BLANKS;
Daniel Veillardb3d14912005-09-04 20:47:39 +000010246 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10247 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
10248 }
Owen Taylor3473f882001-02-23 17:55:21 +000010249}
10250
10251/**
10252 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +000010253 * @name: a name string
10254 *
10255 * Is the name given a NodeType one.
10256 *
10257 * [38] NodeType ::= 'comment'
10258 * | 'text'
10259 * | 'processing-instruction'
10260 * | 'node'
10261 *
10262 * Returns 1 if true 0 otherwise
10263 */
10264int
10265xmlXPathIsNodeType(const xmlChar *name) {
10266 if (name == NULL)
10267 return(0);
10268
Daniel Veillard1971ee22002-01-31 20:29:19 +000010269 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +000010270 return(1);
10271 if (xmlStrEqual(name, BAD_CAST "text"))
10272 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010273 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +000010274 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010275 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +000010276 return(1);
10277 return(0);
10278}
10279
10280/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010281 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +000010282 * @ctxt: the XPath Parser context
10283 *
10284 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010285 * [17] Argument ::= Expr
Owen Taylor3473f882001-02-23 17:55:21 +000010286 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010287 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +000010288 * pushed on the stack
10289 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010290static void
10291xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010292 xmlChar *name;
10293 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010294 int nbargs = 0;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010295 int sort = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010296
10297 name = xmlXPathParseQName(ctxt, &prefix);
10298 if (name == NULL) {
Daniel Veillard074f37e2008-09-01 13:38:22 +000010299 xmlFree(prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010300 XP_ERROR(XPATH_EXPR_ERROR);
10301 }
10302 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010303#ifdef DEBUG_EXPR
10304 if (prefix == NULL)
10305 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10306 name);
10307 else
10308 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10309 prefix, name);
10310#endif
10311
Owen Taylor3473f882001-02-23 17:55:21 +000010312 if (CUR != '(') {
10313 XP_ERROR(XPATH_EXPR_ERROR);
10314 }
10315 NEXT;
10316 SKIP_BLANKS;
10317
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010318 /*
10319 * Optimization for count(): we don't need the node-set to be sorted.
10320 */
10321 if ((prefix == NULL) && (name[0] == 'c') &&
10322 xmlStrEqual(name, BAD_CAST "count"))
10323 {
10324 sort = 0;
10325 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010326 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +000010327 if (CUR != ')') {
10328 while (CUR != 0) {
10329 int op1 = ctxt->comp->last;
10330 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010331 xmlXPathCompileExpr(ctxt, sort);
Daniel Veillard074f37e2008-09-01 13:38:22 +000010332 if (ctxt->error != XPATH_EXPRESSION_OK) {
10333 xmlFree(name);
10334 xmlFree(prefix);
10335 return;
10336 }
Daniel Veillard71f9d732003-01-14 16:07:16 +000010337 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10338 nbargs++;
10339 if (CUR == ')') break;
10340 if (CUR != ',') {
10341 XP_ERROR(XPATH_EXPR_ERROR);
10342 }
10343 NEXT;
10344 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010345 }
Owen Taylor3473f882001-02-23 17:55:21 +000010346 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010347 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10348 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010349 NEXT;
10350 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010351}
10352
10353/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010354 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010355 * @ctxt: the XPath Parser context
10356 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010357 * [15] PrimaryExpr ::= VariableReference
Owen Taylor3473f882001-02-23 17:55:21 +000010358 * | '(' Expr ')'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010359 * | Literal
10360 * | Number
10361 * | FunctionCall
Owen Taylor3473f882001-02-23 17:55:21 +000010362 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010363 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010364 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010365static void
10366xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010367 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010368 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010369 else if (CUR == '(') {
10370 NEXT;
10371 SKIP_BLANKS;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010372 xmlXPathCompileExpr(ctxt, 1);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010373 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000010374 if (CUR != ')') {
10375 XP_ERROR(XPATH_EXPR_ERROR);
10376 }
10377 NEXT;
10378 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010379 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010380 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010381 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010382 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010383 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010384 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010385 }
10386 SKIP_BLANKS;
10387}
10388
10389/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010390 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010391 * @ctxt: the XPath Parser context
10392 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010393 * [20] FilterExpr ::= PrimaryExpr
10394 * | FilterExpr Predicate
Owen Taylor3473f882001-02-23 17:55:21 +000010395 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010396 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010397 * Square brackets are used to filter expressions in the same way that
10398 * they are used in location paths. It is an error if the expression to
10399 * be filtered does not evaluate to a node-set. The context node list
10400 * used for evaluating the expression in square brackets is the node-set
10401 * to be filtered listed in document order.
10402 */
10403
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010404static void
10405xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10406 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010407 CHECK_ERROR;
10408 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010409
Owen Taylor3473f882001-02-23 17:55:21 +000010410 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010411 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +000010412 SKIP_BLANKS;
10413 }
10414
Daniel Veillard45490ae2008-07-29 09:13:19 +000010415
Owen Taylor3473f882001-02-23 17:55:21 +000010416}
10417
10418/**
10419 * xmlXPathScanName:
10420 * @ctxt: the XPath Parser context
10421 *
10422 * Trickery: parse an XML name but without consuming the input flow
10423 * Needed to avoid insanity in the parser state.
10424 *
10425 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10426 * CombiningChar | Extender
10427 *
10428 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10429 *
10430 * [6] Names ::= Name (S Name)*
10431 *
10432 * Returns the Name parsed or NULL
10433 */
10434
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010435static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +000010436xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +000010437 int len = 0, l;
10438 int c;
Daniel Veillard03226812004-11-01 14:55:21 +000010439 const xmlChar *cur;
10440 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +000010441
Daniel Veillard03226812004-11-01 14:55:21 +000010442 cur = ctxt->cur;
10443
10444 c = CUR_CHAR(l);
10445 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10446 (!IS_LETTER(c) && (c != '_') &&
10447 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010448 return(NULL);
10449 }
10450
Daniel Veillard03226812004-11-01 14:55:21 +000010451 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10452 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10453 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000010454 (c == '_') || (c == ':') ||
Daniel Veillard03226812004-11-01 14:55:21 +000010455 (IS_COMBINING(c)) ||
10456 (IS_EXTENDER(c)))) {
10457 len += l;
10458 NEXTL(l);
10459 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +000010460 }
Daniel Veillard03226812004-11-01 14:55:21 +000010461 ret = xmlStrndup(cur, ctxt->cur - cur);
10462 ctxt->cur = cur;
10463 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +000010464}
10465
10466/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010467 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010468 * @ctxt: the XPath Parser context
10469 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010470 * [19] PathExpr ::= LocationPath
10471 * | FilterExpr
10472 * | FilterExpr '/' RelativeLocationPath
10473 * | FilterExpr '//' RelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000010474 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010475 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010476 * The / operator and // operators combine an arbitrary expression
10477 * and a relative location path. It is an error if the expression
10478 * does not evaluate to a node-set.
10479 * The / operator does composition in the same way as when / is
10480 * used in a location path. As in location paths, // is short for
10481 * /descendant-or-self::node()/.
10482 */
10483
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010484static void
10485xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010486 int lc = 1; /* Should we branch to LocationPath ? */
10487 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10488
10489 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010490 if ((CUR == '$') || (CUR == '(') ||
10491 (IS_ASCII_DIGIT(CUR)) ||
William M. Brackd1757ab2004-10-02 22:07:48 +000010492 (CUR == '\'') || (CUR == '"') ||
10493 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010494 lc = 0;
10495 } else if (CUR == '*') {
10496 /* relative or absolute location path */
10497 lc = 1;
10498 } else if (CUR == '/') {
10499 /* relative or absolute location path */
10500 lc = 1;
10501 } else if (CUR == '@') {
10502 /* relative abbreviated attribute location path */
10503 lc = 1;
10504 } else if (CUR == '.') {
10505 /* relative abbreviated attribute location path */
10506 lc = 1;
10507 } else {
10508 /*
10509 * Problem is finding if we have a name here whether it's:
10510 * - a nodetype
10511 * - a function call in which case it's followed by '('
10512 * - an axis in which case it's followed by ':'
10513 * - a element name
10514 * We do an a priori analysis here rather than having to
10515 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +000010516 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +000010517 * read/write/debug.
10518 */
10519 SKIP_BLANKS;
10520 name = xmlXPathScanName(ctxt);
10521 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10522#ifdef DEBUG_STEP
10523 xmlGenericError(xmlGenericErrorContext,
10524 "PathExpr: Axis\n");
10525#endif
10526 lc = 1;
10527 xmlFree(name);
10528 } else if (name != NULL) {
10529 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +000010530
Daniel Veillard45490ae2008-07-29 09:13:19 +000010531
Owen Taylor3473f882001-02-23 17:55:21 +000010532 while (NXT(len) != 0) {
10533 if (NXT(len) == '/') {
10534 /* element name */
10535#ifdef DEBUG_STEP
10536 xmlGenericError(xmlGenericErrorContext,
10537 "PathExpr: AbbrRelLocation\n");
10538#endif
10539 lc = 1;
10540 break;
William M. Brack76e95df2003-10-18 16:20:14 +000010541 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +000010542 /* ignore blanks */
10543 ;
Owen Taylor3473f882001-02-23 17:55:21 +000010544 } else if (NXT(len) == ':') {
10545#ifdef DEBUG_STEP
10546 xmlGenericError(xmlGenericErrorContext,
10547 "PathExpr: AbbrRelLocation\n");
10548#endif
10549 lc = 1;
10550 break;
10551 } else if ((NXT(len) == '(')) {
10552 /* Note Type or Function */
10553 if (xmlXPathIsNodeType(name)) {
10554#ifdef DEBUG_STEP
10555 xmlGenericError(xmlGenericErrorContext,
10556 "PathExpr: Type search\n");
10557#endif
10558 lc = 1;
10559 } else {
10560#ifdef DEBUG_STEP
10561 xmlGenericError(xmlGenericErrorContext,
10562 "PathExpr: function call\n");
10563#endif
10564 lc = 0;
10565 }
10566 break;
10567 } else if ((NXT(len) == '[')) {
10568 /* element name */
10569#ifdef DEBUG_STEP
10570 xmlGenericError(xmlGenericErrorContext,
10571 "PathExpr: AbbrRelLocation\n");
10572#endif
10573 lc = 1;
10574 break;
10575 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10576 (NXT(len) == '=')) {
10577 lc = 1;
10578 break;
10579 } else {
10580 lc = 1;
10581 break;
10582 }
10583 len++;
10584 }
10585 if (NXT(len) == 0) {
10586#ifdef DEBUG_STEP
10587 xmlGenericError(xmlGenericErrorContext,
10588 "PathExpr: AbbrRelLocation\n");
10589#endif
10590 /* element name */
10591 lc = 1;
10592 }
10593 xmlFree(name);
10594 } else {
William M. Brack08171912003-12-29 02:52:11 +000010595 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +000010596 XP_ERROR(XPATH_EXPR_ERROR);
10597 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000010598 }
Owen Taylor3473f882001-02-23 17:55:21 +000010599
10600 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010601 if (CUR == '/') {
10602 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10603 } else {
10604 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010605 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010606 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010607 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010608 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010609 CHECK_ERROR;
10610 if ((CUR == '/') && (NXT(1) == '/')) {
10611 SKIP(2);
10612 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010613
10614 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10615 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10616 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10617
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010618 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010619 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010620 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010621 }
10622 }
10623 SKIP_BLANKS;
10624}
10625
10626/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010627 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010628 * @ctxt: the XPath Parser context
10629 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010630 * [18] UnionExpr ::= PathExpr
10631 * | UnionExpr '|' PathExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010632 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010633 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010634 */
10635
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010636static void
10637xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10638 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010639 CHECK_ERROR;
10640 SKIP_BLANKS;
10641 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010642 int op1 = ctxt->comp->last;
10643 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010644
10645 NEXT;
10646 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010647 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010648
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010649 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10650
Owen Taylor3473f882001-02-23 17:55:21 +000010651 SKIP_BLANKS;
10652 }
Owen Taylor3473f882001-02-23 17:55:21 +000010653}
10654
10655/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010656 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010657 * @ctxt: the XPath Parser context
10658 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010659 * [27] UnaryExpr ::= UnionExpr
10660 * | '-' UnaryExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010661 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010662 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010663 */
10664
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010665static void
10666xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010667 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010668 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010669
10670 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +000010671 while (CUR == '-') {
10672 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010673 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010674 NEXT;
10675 SKIP_BLANKS;
10676 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010677
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010678 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010679 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010680 if (found) {
10681 if (minus)
10682 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10683 else
10684 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010685 }
10686}
10687
10688/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010689 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010690 * @ctxt: the XPath Parser context
10691 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010692 * [26] MultiplicativeExpr ::= UnaryExpr
10693 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10694 * | MultiplicativeExpr 'div' UnaryExpr
10695 * | MultiplicativeExpr 'mod' UnaryExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010696 * [34] MultiplyOperator ::= '*'
10697 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010698 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010699 */
10700
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010701static void
10702xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10703 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010704 CHECK_ERROR;
10705 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010706 while ((CUR == '*') ||
Owen Taylor3473f882001-02-23 17:55:21 +000010707 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10708 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10709 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010710 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010711
10712 if (CUR == '*') {
10713 op = 0;
10714 NEXT;
10715 } else if (CUR == 'd') {
10716 op = 1;
10717 SKIP(3);
10718 } else if (CUR == 'm') {
10719 op = 2;
10720 SKIP(3);
10721 }
10722 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010723 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010724 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010725 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010726 SKIP_BLANKS;
10727 }
10728}
10729
10730/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010731 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010732 * @ctxt: the XPath Parser context
10733 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010734 * [25] AdditiveExpr ::= MultiplicativeExpr
10735 * | AdditiveExpr '+' MultiplicativeExpr
10736 * | AdditiveExpr '-' MultiplicativeExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010737 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010738 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010739 */
10740
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010741static void
10742xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010743
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010744 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010745 CHECK_ERROR;
10746 SKIP_BLANKS;
10747 while ((CUR == '+') || (CUR == '-')) {
10748 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010749 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010750
10751 if (CUR == '+') plus = 1;
10752 else plus = 0;
10753 NEXT;
10754 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010755 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010756 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010757 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010758 SKIP_BLANKS;
10759 }
10760}
10761
10762/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010763 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010764 * @ctxt: the XPath Parser context
10765 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010766 * [24] RelationalExpr ::= AdditiveExpr
10767 * | RelationalExpr '<' AdditiveExpr
10768 * | RelationalExpr '>' AdditiveExpr
10769 * | RelationalExpr '<=' AdditiveExpr
10770 * | RelationalExpr '>=' AdditiveExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010771 *
10772 * A <= B > C is allowed ? Answer from James, yes with
10773 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10774 * which is basically what got implemented.
10775 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010776 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +000010777 * on the stack
10778 */
10779
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010780static void
10781xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10782 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010783 CHECK_ERROR;
10784 SKIP_BLANKS;
10785 while ((CUR == '<') ||
10786 (CUR == '>') ||
10787 ((CUR == '<') && (NXT(1) == '=')) ||
10788 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010789 int inf, strict;
10790 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010791
10792 if (CUR == '<') inf = 1;
10793 else inf = 0;
10794 if (NXT(1) == '=') strict = 0;
10795 else strict = 1;
10796 NEXT;
10797 if (!strict) NEXT;
10798 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010799 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010800 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010801 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +000010802 SKIP_BLANKS;
10803 }
10804}
10805
10806/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010807 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010808 * @ctxt: the XPath Parser context
10809 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010810 * [23] EqualityExpr ::= RelationalExpr
10811 * | EqualityExpr '=' RelationalExpr
10812 * | EqualityExpr '!=' RelationalExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010813 *
10814 * A != B != C is allowed ? Answer from James, yes with
10815 * (RelationalExpr = RelationalExpr) = RelationalExpr
10816 * (RelationalExpr != RelationalExpr) != RelationalExpr
10817 * which is basically what got implemented.
10818 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010819 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010820 *
10821 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010822static void
10823xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10824 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010825 CHECK_ERROR;
10826 SKIP_BLANKS;
10827 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010828 int eq;
10829 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010830
10831 if (CUR == '=') eq = 1;
10832 else eq = 0;
10833 NEXT;
10834 if (!eq) NEXT;
10835 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010836 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010837 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010838 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010839 SKIP_BLANKS;
10840 }
10841}
10842
10843/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010844 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010845 * @ctxt: the XPath Parser context
10846 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010847 * [22] AndExpr ::= EqualityExpr
10848 * | AndExpr 'and' EqualityExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010849 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010850 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010851 *
10852 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010853static void
10854xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10855 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010856 CHECK_ERROR;
10857 SKIP_BLANKS;
10858 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010859 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010860 SKIP(3);
10861 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010862 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010863 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010864 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010865 SKIP_BLANKS;
10866 }
10867}
10868
10869/**
Daniel Veillard591b4be2003-02-09 23:33:36 +000010870 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010871 * @ctxt: the XPath Parser context
10872 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010873 * [14] Expr ::= OrExpr
10874 * [21] OrExpr ::= AndExpr
10875 * | OrExpr 'or' AndExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010876 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010877 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +000010878 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010879static void
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010880xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010881 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010882 CHECK_ERROR;
10883 SKIP_BLANKS;
10884 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010885 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010886 SKIP(2);
10887 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010888 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010889 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010890 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010891 SKIP_BLANKS;
10892 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010893 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010894 /* more ops could be optimized too */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010895 /*
10896 * This is the main place to eliminate sorting for
10897 * operations which don't require a sorted node-set.
10898 * E.g. count().
10899 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010900 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10901 }
Owen Taylor3473f882001-02-23 17:55:21 +000010902}
10903
10904/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010905 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +000010906 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010907 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +000010908 *
10909 * [8] Predicate ::= '[' PredicateExpr ']'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010910 * [9] PredicateExpr ::= Expr
Owen Taylor3473f882001-02-23 17:55:21 +000010911 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010912 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +000010913 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010914static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010915xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010916 int op1 = ctxt->comp->last;
10917
10918 SKIP_BLANKS;
10919 if (CUR != '[') {
10920 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10921 }
10922 NEXT;
10923 SKIP_BLANKS;
10924
10925 ctxt->comp->last = -1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000010926 /*
10927 * This call to xmlXPathCompileExpr() will deactivate sorting
10928 * of the predicate result.
10929 * TODO: Sorting is still activated for filters, since I'm not
10930 * sure if needed. Normally sorting should not be needed, since
10931 * a filter can only diminish the number of items in a sequence,
10932 * but won't change its order; so if the initial sequence is sorted,
10933 * subsequent sorting is not needed.
10934 */
10935 if (! filter)
10936 xmlXPathCompileExpr(ctxt, 0);
10937 else
10938 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010939 CHECK_ERROR;
10940
10941 if (CUR != ']') {
10942 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10943 }
10944
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010945 if (filter)
10946 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10947 else
10948 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010949
10950 NEXT;
10951 SKIP_BLANKS;
10952}
10953
10954/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010955 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +000010956 * @ctxt: the XPath Parser context
10957 * @test: pointer to a xmlXPathTestVal
10958 * @type: pointer to a xmlXPathTypeVal
10959 * @prefix: placeholder for a possible name prefix
10960 *
10961 * [7] NodeTest ::= NameTest
10962 * | NodeType '(' ')'
10963 * | 'processing-instruction' '(' Literal ')'
10964 *
10965 * [37] NameTest ::= '*'
10966 * | NCName ':' '*'
10967 * | QName
10968 * [38] NodeType ::= 'comment'
10969 * | 'text'
10970 * | 'processing-instruction'
10971 * | 'node'
10972 *
William M. Brack08171912003-12-29 02:52:11 +000010973 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +000010974 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010975static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010976xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10977 xmlXPathTypeVal *type, const xmlChar **prefix,
10978 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +000010979 int blanks;
10980
10981 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10982 STRANGE;
10983 return(NULL);
10984 }
William M. Brack78637da2003-07-31 14:47:38 +000010985 *type = (xmlXPathTypeVal) 0;
10986 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010987 *prefix = NULL;
10988 SKIP_BLANKS;
10989
10990 if ((name == NULL) && (CUR == '*')) {
10991 /*
10992 * All elements
10993 */
10994 NEXT;
10995 *test = NODE_TEST_ALL;
10996 return(NULL);
10997 }
10998
10999 if (name == NULL)
11000 name = xmlXPathParseNCName(ctxt);
11001 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011002 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011003 }
11004
William M. Brack76e95df2003-10-18 16:20:14 +000011005 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +000011006 SKIP_BLANKS;
11007 if (CUR == '(') {
11008 NEXT;
11009 /*
11010 * NodeType or PI search
11011 */
11012 if (xmlStrEqual(name, BAD_CAST "comment"))
11013 *type = NODE_TYPE_COMMENT;
11014 else if (xmlStrEqual(name, BAD_CAST "node"))
11015 *type = NODE_TYPE_NODE;
11016 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11017 *type = NODE_TYPE_PI;
11018 else if (xmlStrEqual(name, BAD_CAST "text"))
11019 *type = NODE_TYPE_TEXT;
11020 else {
11021 if (name != NULL)
11022 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000011023 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011024 }
11025
11026 *test = NODE_TEST_TYPE;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011027
Owen Taylor3473f882001-02-23 17:55:21 +000011028 SKIP_BLANKS;
11029 if (*type == NODE_TYPE_PI) {
11030 /*
11031 * Specific case: search a PI by name.
11032 */
Owen Taylor3473f882001-02-23 17:55:21 +000011033 if (name != NULL)
11034 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +000011035 name = NULL;
11036 if (CUR != ')') {
11037 name = xmlXPathParseLiteral(ctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000011038 CHECK_ERROR NULL;
Daniel Veillarded23b7d2002-05-27 12:16:02 +000011039 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +000011040 SKIP_BLANKS;
11041 }
Owen Taylor3473f882001-02-23 17:55:21 +000011042 }
11043 if (CUR != ')') {
11044 if (name != NULL)
11045 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000011046 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011047 }
11048 NEXT;
11049 return(name);
11050 }
11051 *test = NODE_TEST_NAME;
11052 if ((!blanks) && (CUR == ':')) {
11053 NEXT;
11054
11055 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011056 * Since currently the parser context don't have a
11057 * namespace list associated:
11058 * The namespace name for this prefix can be computed
11059 * only at evaluation time. The compilation is done
11060 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +000011061 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011062#if 0
Owen Taylor3473f882001-02-23 17:55:21 +000011063 *prefix = xmlXPathNsLookup(ctxt->context, name);
11064 if (name != NULL)
11065 xmlFree(name);
11066 if (*prefix == NULL) {
11067 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11068 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011069#else
11070 *prefix = name;
11071#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011072
11073 if (CUR == '*') {
11074 /*
11075 * All elements
11076 */
11077 NEXT;
11078 *test = NODE_TEST_ALL;
11079 return(NULL);
11080 }
11081
11082 name = xmlXPathParseNCName(ctxt);
11083 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011084 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011085 }
11086 }
11087 return(name);
11088}
11089
11090/**
11091 * xmlXPathIsAxisName:
11092 * @name: a preparsed name token
11093 *
11094 * [6] AxisName ::= 'ancestor'
11095 * | 'ancestor-or-self'
11096 * | 'attribute'
11097 * | 'child'
11098 * | 'descendant'
11099 * | 'descendant-or-self'
11100 * | 'following'
11101 * | 'following-sibling'
11102 * | 'namespace'
11103 * | 'parent'
11104 * | 'preceding'
11105 * | 'preceding-sibling'
11106 * | 'self'
11107 *
11108 * Returns the axis or 0
11109 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011110static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +000011111xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +000011112 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011113 switch (name[0]) {
11114 case 'a':
11115 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11116 ret = AXIS_ANCESTOR;
11117 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11118 ret = AXIS_ANCESTOR_OR_SELF;
11119 if (xmlStrEqual(name, BAD_CAST "attribute"))
11120 ret = AXIS_ATTRIBUTE;
11121 break;
11122 case 'c':
11123 if (xmlStrEqual(name, BAD_CAST "child"))
11124 ret = AXIS_CHILD;
11125 break;
11126 case 'd':
11127 if (xmlStrEqual(name, BAD_CAST "descendant"))
11128 ret = AXIS_DESCENDANT;
11129 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11130 ret = AXIS_DESCENDANT_OR_SELF;
11131 break;
11132 case 'f':
11133 if (xmlStrEqual(name, BAD_CAST "following"))
11134 ret = AXIS_FOLLOWING;
11135 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11136 ret = AXIS_FOLLOWING_SIBLING;
11137 break;
11138 case 'n':
11139 if (xmlStrEqual(name, BAD_CAST "namespace"))
11140 ret = AXIS_NAMESPACE;
11141 break;
11142 case 'p':
11143 if (xmlStrEqual(name, BAD_CAST "parent"))
11144 ret = AXIS_PARENT;
11145 if (xmlStrEqual(name, BAD_CAST "preceding"))
11146 ret = AXIS_PRECEDING;
11147 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11148 ret = AXIS_PRECEDING_SIBLING;
11149 break;
11150 case 's':
11151 if (xmlStrEqual(name, BAD_CAST "self"))
11152 ret = AXIS_SELF;
11153 break;
11154 }
11155 return(ret);
11156}
11157
11158/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011159 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +000011160 * @ctxt: the XPath Parser context
11161 *
11162 * [4] Step ::= AxisSpecifier NodeTest Predicate*
Daniel Veillard45490ae2008-07-29 09:13:19 +000011163 * | AbbreviatedStep
Owen Taylor3473f882001-02-23 17:55:21 +000011164 *
11165 * [12] AbbreviatedStep ::= '.' | '..'
11166 *
11167 * [5] AxisSpecifier ::= AxisName '::'
11168 * | AbbreviatedAxisSpecifier
11169 *
11170 * [13] AbbreviatedAxisSpecifier ::= '@'?
11171 *
11172 * Modified for XPtr range support as:
11173 *
11174 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11175 * | AbbreviatedStep
11176 * | 'range-to' '(' Expr ')' Predicate*
11177 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011178 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +000011179 * A location step of . is short for self::node(). This is
11180 * particularly useful in conjunction with //. For example, the
11181 * location path .//para is short for
11182 * self::node()/descendant-or-self::node()/child::para
11183 * and so will select all para descendant elements of the context
11184 * node.
11185 * Similarly, a location step of .. is short for parent::node().
11186 * For example, ../title is short for parent::node()/child::title
11187 * and so will select the title children of the parent of the context
11188 * node.
11189 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011190static void
11191xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011192#ifdef LIBXML_XPTR_ENABLED
11193 int rangeto = 0;
11194 int op2 = -1;
11195#endif
11196
Owen Taylor3473f882001-02-23 17:55:21 +000011197 SKIP_BLANKS;
11198 if ((CUR == '.') && (NXT(1) == '.')) {
11199 SKIP(2);
11200 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011201 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11202 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011203 } else if (CUR == '.') {
11204 NEXT;
11205 SKIP_BLANKS;
11206 } else {
11207 xmlChar *name = NULL;
11208 const xmlChar *prefix = NULL;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011209 xmlXPathTestVal test = (xmlXPathTestVal) 0;
William M. Brack78637da2003-07-31 14:47:38 +000011210 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011211 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011212 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +000011213
11214 /*
11215 * The modification needed for XPointer change to the production
11216 */
11217#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011218 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +000011219 name = xmlXPathParseNCName(ctxt);
11220 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011221 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011222 xmlFree(name);
11223 SKIP_BLANKS;
11224 if (CUR != '(') {
11225 XP_ERROR(XPATH_EXPR_ERROR);
11226 }
11227 NEXT;
11228 SKIP_BLANKS;
11229
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011230 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011231 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +000011232 CHECK_ERROR;
11233
11234 SKIP_BLANKS;
11235 if (CUR != ')') {
11236 XP_ERROR(XPATH_EXPR_ERROR);
11237 }
11238 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011239 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000011240 goto eval_predicates;
11241 }
11242 }
11243#endif
Daniel Veillard2156a562001-04-28 12:24:34 +000011244 if (CUR == '*') {
11245 axis = AXIS_CHILD;
11246 } else {
11247 if (name == NULL)
11248 name = xmlXPathParseNCName(ctxt);
11249 if (name != NULL) {
11250 axis = xmlXPathIsAxisName(name);
11251 if (axis != 0) {
11252 SKIP_BLANKS;
11253 if ((CUR == ':') && (NXT(1) == ':')) {
11254 SKIP(2);
11255 xmlFree(name);
11256 name = NULL;
11257 } else {
11258 /* an element name can conflict with an axis one :-\ */
11259 axis = AXIS_CHILD;
11260 }
Owen Taylor3473f882001-02-23 17:55:21 +000011261 } else {
Owen Taylor3473f882001-02-23 17:55:21 +000011262 axis = AXIS_CHILD;
11263 }
Daniel Veillard2156a562001-04-28 12:24:34 +000011264 } else if (CUR == '@') {
11265 NEXT;
11266 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +000011267 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +000011268 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +000011269 }
Owen Taylor3473f882001-02-23 17:55:21 +000011270 }
11271
Daniel Veillard2f3523f2010-10-15 18:30:29 +020011272 if (ctxt->error != XPATH_EXPRESSION_OK) {
11273 xmlFree(name);
11274 return;
11275 }
Owen Taylor3473f882001-02-23 17:55:21 +000011276
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011277 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +000011278 if (test == 0)
11279 return;
11280
Daniel Veillarded6c5492005-07-23 15:00:22 +000011281 if ((prefix != NULL) && (ctxt->context != NULL) &&
11282 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11283 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11284 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11285 }
11286 }
Owen Taylor3473f882001-02-23 17:55:21 +000011287#ifdef DEBUG_STEP
11288 xmlGenericError(xmlGenericErrorContext,
11289 "Basis : computing new set\n");
11290#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011291
Owen Taylor3473f882001-02-23 17:55:21 +000011292#ifdef DEBUG_STEP
11293 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011294 if (ctxt->value == NULL)
11295 xmlGenericError(xmlGenericErrorContext, "no value\n");
11296 else if (ctxt->value->nodesetval == NULL)
11297 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11298 else
11299 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011300#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011301
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011302#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +000011303eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011304#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011305 op1 = ctxt->comp->last;
11306 ctxt->comp->last = -1;
11307
Owen Taylor3473f882001-02-23 17:55:21 +000011308 SKIP_BLANKS;
11309 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011310 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011311 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011312
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011313#ifdef LIBXML_XPTR_ENABLED
11314 if (rangeto) {
11315 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11316 } else
11317#endif
11318 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11319 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011320
Owen Taylor3473f882001-02-23 17:55:21 +000011321 }
11322#ifdef DEBUG_STEP
11323 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011324 if (ctxt->value == NULL)
11325 xmlGenericError(xmlGenericErrorContext, "no value\n");
11326 else if (ctxt->value->nodesetval == NULL)
11327 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11328 else
11329 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11330 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011331#endif
11332}
11333
11334/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011335 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011336 * @ctxt: the XPath Parser context
11337 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011338 * [3] RelativeLocationPath ::= Step
11339 * | RelativeLocationPath '/' Step
11340 * | AbbreviatedRelativeLocationPath
11341 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
Owen Taylor3473f882001-02-23 17:55:21 +000011342 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011343 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +000011344 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011345static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011346xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011347(xmlXPathParserContextPtr ctxt) {
11348 SKIP_BLANKS;
11349 if ((CUR == '/') && (NXT(1) == '/')) {
11350 SKIP(2);
11351 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011352 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11353 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011354 } else if (CUR == '/') {
11355 NEXT;
11356 SKIP_BLANKS;
11357 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011358 xmlXPathCompStep(ctxt);
Martin729601f2009-10-12 22:42:26 +020011359 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000011360 SKIP_BLANKS;
11361 while (CUR == '/') {
11362 if ((CUR == '/') && (NXT(1) == '/')) {
11363 SKIP(2);
11364 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011365 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +000011366 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011367 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011368 } else if (CUR == '/') {
11369 NEXT;
11370 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011371 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011372 }
11373 SKIP_BLANKS;
11374 }
11375}
11376
11377/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011378 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011379 * @ctxt: the XPath Parser context
11380 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011381 * [1] LocationPath ::= RelativeLocationPath
11382 * | AbsoluteLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011383 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
Daniel Veillard45490ae2008-07-29 09:13:19 +000011384 * | AbbreviatedAbsoluteLocationPath
11385 * [10] AbbreviatedAbsoluteLocationPath ::=
11386 * '//' RelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011387 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011388 * Compile a location path
11389 *
Owen Taylor3473f882001-02-23 17:55:21 +000011390 * // is short for /descendant-or-self::node()/. For example,
11391 * //para is short for /descendant-or-self::node()/child::para and
11392 * so will select any para element in the document (even a para element
11393 * that is a document element will be selected by //para since the
11394 * document element node is a child of the root node); div//para is
11395 * short for div/descendant-or-self::node()/child::para and so will
11396 * select all para descendants of div children.
11397 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011398static void
11399xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000011400 SKIP_BLANKS;
11401 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011402 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011403 } else {
11404 while (CUR == '/') {
11405 if ((CUR == '/') && (NXT(1) == '/')) {
11406 SKIP(2);
11407 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011408 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11409 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011410 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011411 } else if (CUR == '/') {
11412 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +000011413 SKIP_BLANKS;
11414 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +000011415 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +000011416 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011417 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011418 }
Martin729601f2009-10-12 22:42:26 +020011419 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000011420 }
11421 }
11422}
11423
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011424/************************************************************************
11425 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011426 * XPath precompiled expression evaluation *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011427 * *
11428 ************************************************************************/
11429
Daniel Veillardf06307e2001-07-03 10:35:50 +000011430static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011431xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11432
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011433#ifdef DEBUG_STEP
11434static void
Daniel Veillard074f37e2008-09-01 13:38:22 +000011435xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011436 int nbNodes)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011437{
Daniel Veillardf06307e2001-07-03 10:35:50 +000011438 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillard074f37e2008-09-01 13:38:22 +000011439 switch (op->value) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011440 case AXIS_ANCESTOR:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011441 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011442 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011443 case AXIS_ANCESTOR_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011444 xmlGenericError(xmlGenericErrorContext,
11445 "axis 'ancestors-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011446 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011447 case AXIS_ATTRIBUTE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011448 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011449 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011450 case AXIS_CHILD:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011451 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011452 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011453 case AXIS_DESCENDANT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011454 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011455 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011456 case AXIS_DESCENDANT_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011457 xmlGenericError(xmlGenericErrorContext,
11458 "axis 'descendant-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011459 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011460 case AXIS_FOLLOWING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011461 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011462 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011463 case AXIS_FOLLOWING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011464 xmlGenericError(xmlGenericErrorContext,
11465 "axis 'following-siblings' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011466 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011467 case AXIS_NAMESPACE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011468 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011469 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011470 case AXIS_PARENT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011471 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011472 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011473 case AXIS_PRECEDING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011474 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011475 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011476 case AXIS_PRECEDING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011477 xmlGenericError(xmlGenericErrorContext,
11478 "axis 'preceding-sibling' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011479 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011480 case AXIS_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011481 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011482 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011483 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011484 xmlGenericError(xmlGenericErrorContext,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011485 " context contains %d nodes\n", nbNodes);
Daniel Veillard074f37e2008-09-01 13:38:22 +000011486 switch (op->value2) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011487 case NODE_TEST_NONE:
11488 xmlGenericError(xmlGenericErrorContext,
11489 " searching for none !!!\n");
11490 break;
11491 case NODE_TEST_TYPE:
11492 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011493 " searching for type %d\n", op->value3);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011494 break;
11495 case NODE_TEST_PI:
11496 xmlGenericError(xmlGenericErrorContext,
11497 " searching for PI !!!\n");
11498 break;
11499 case NODE_TEST_ALL:
11500 xmlGenericError(xmlGenericErrorContext,
11501 " searching for *\n");
11502 break;
11503 case NODE_TEST_NS:
11504 xmlGenericError(xmlGenericErrorContext,
11505 " searching for namespace %s\n",
Daniel Veillard074f37e2008-09-01 13:38:22 +000011506 op->value5);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011507 break;
11508 case NODE_TEST_NAME:
11509 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011510 " searching for name %s\n", op->value5);
11511 if (op->value4)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011512 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011513 " with namespace %s\n", op->value4);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011514 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011515 }
11516 xmlGenericError(xmlGenericErrorContext, "Testing : ");
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011517}
11518#endif /* DEBUG_STEP */
11519
11520static int
11521xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11522 xmlXPathStepOpPtr op,
11523 xmlNodeSetPtr set,
11524 int contextSize,
11525 int hasNsNodes)
11526{
11527 if (op->ch1 != -1) {
11528 xmlXPathCompExprPtr comp = ctxt->comp;
11529 /*
11530 * Process inner predicates first.
11531 */
11532 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11533 /*
11534 * TODO: raise an internal error.
11535 */
11536 }
11537 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11538 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11539 CHECK_ERROR0;
11540 if (contextSize <= 0)
11541 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011542 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011543 if (op->ch2 != -1) {
11544 xmlXPathContextPtr xpctxt = ctxt->context;
11545 xmlNodePtr contextNode, oldContextNode;
11546 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011547 int i, res, contextPos = 0, newContextSize;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011548 xmlXPathStepOpPtr exprOp;
11549 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11550
11551#ifdef LIBXML_XPTR_ENABLED
11552 /*
11553 * URGENT TODO: Check the following:
11554 * We don't expect location sets if evaluating prediates, right?
11555 * Only filters should expect location sets, right?
11556 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011557#endif
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011558 /*
11559 * SPEC XPath 1.0:
11560 * "For each node in the node-set to be filtered, the
11561 * PredicateExpr is evaluated with that node as the
11562 * context node, with the number of nodes in the
11563 * node-set as the context size, and with the proximity
11564 * position of the node in the node-set with respect to
11565 * the axis as the context position;"
11566 * @oldset is the node-set" to be filtered.
11567 *
11568 * SPEC XPath 1.0:
11569 * "only predicates change the context position and
11570 * context size (see [2.4 Predicates])."
11571 * Example:
11572 * node-set context pos
11573 * nA 1
11574 * nB 2
11575 * nC 3
11576 * After applying predicate [position() > 1] :
11577 * node-set context pos
11578 * nB 1
11579 * nC 2
11580 */
11581 oldContextNode = xpctxt->node;
11582 oldContextDoc = xpctxt->doc;
11583 /*
11584 * Get the expression of this predicate.
11585 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000011586 exprOp = &ctxt->comp->steps[op->ch2];
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011587 newContextSize = 0;
11588 for (i = 0; i < set->nodeNr; i++) {
11589 if (set->nodeTab[i] == NULL)
11590 continue;
11591
11592 contextNode = set->nodeTab[i];
11593 xpctxt->node = contextNode;
11594 xpctxt->contextSize = contextSize;
11595 xpctxt->proximityPosition = ++contextPos;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011596
11597 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011598 * Also set the xpath document in case things like
11599 * key() are evaluated in the predicate.
11600 */
11601 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11602 (contextNode->doc != NULL))
11603 xpctxt->doc = contextNode->doc;
11604 /*
11605 * Evaluate the predicate expression with 1 context node
11606 * at a time; this node is packaged into a node set; this
11607 * node set is handed over to the evaluation mechanism.
11608 */
11609 if (contextObj == NULL)
11610 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11611 else
11612 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11613 contextNode);
11614
11615 valuePush(ctxt, contextObj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011616
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011617 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011618
William M. Brack0bcec062007-02-14 02:15:19 +000011619 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11620 xmlXPathNodeSetClear(set, hasNsNodes);
11621 newContextSize = 0;
11622 goto evaluation_exit;
11623 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011624
11625 if (res != 0) {
11626 newContextSize++;
11627 } else {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011628 /*
11629 * Remove the entry from the initial node set.
11630 */
11631 set->nodeTab[i] = NULL;
11632 if (contextNode->type == XML_NAMESPACE_DECL)
11633 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011634 }
11635 if (ctxt->value == contextObj) {
11636 /*
11637 * Don't free the temporary XPath object holding the
11638 * context node, in order to avoid massive recreation
11639 * inside this loop.
11640 */
11641 valuePop(ctxt);
11642 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11643 } else {
11644 /*
11645 * TODO: The object was lost in the evaluation machinery.
11646 * Can this happen? Maybe in internal-error cases.
11647 */
11648 contextObj = NULL;
11649 }
11650 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011651
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011652 if (contextObj != NULL) {
11653 if (ctxt->value == contextObj)
11654 valuePop(ctxt);
11655 xmlXPathReleaseObject(xpctxt, contextObj);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011656 }
William M. Brack0bcec062007-02-14 02:15:19 +000011657evaluation_exit:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011658 if (exprRes != NULL)
11659 xmlXPathReleaseObject(ctxt->context, exprRes);
11660 /*
11661 * Reset/invalidate the context.
11662 */
11663 xpctxt->node = oldContextNode;
11664 xpctxt->doc = oldContextDoc;
11665 xpctxt->contextSize = -1;
11666 xpctxt->proximityPosition = -1;
11667 return(newContextSize);
11668 }
11669 return(contextSize);
11670}
11671
11672static int
11673xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11674 xmlXPathStepOpPtr op,
11675 xmlNodeSetPtr set,
11676 int contextSize,
11677 int minPos,
11678 int maxPos,
11679 int hasNsNodes)
11680{
11681 if (op->ch1 != -1) {
11682 xmlXPathCompExprPtr comp = ctxt->comp;
11683 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11684 /*
11685 * TODO: raise an internal error.
11686 */
11687 }
11688 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11689 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11690 CHECK_ERROR0;
11691 if (contextSize <= 0)
11692 return(0);
11693 }
11694 /*
11695 * Check if the node set contains a sufficient number of nodes for
11696 * the requested range.
11697 */
11698 if (contextSize < minPos) {
11699 xmlXPathNodeSetClear(set, hasNsNodes);
11700 return(0);
11701 }
11702 if (op->ch2 == -1) {
11703 /*
11704 * TODO: Can this ever happen?
11705 */
11706 return (contextSize);
11707 } else {
11708 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011709 int i, pos = 0, newContextSize = 0, contextPos = 0, res;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011710 xmlXPathStepOpPtr exprOp;
11711 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11712 xmlNodePtr oldContextNode, contextNode = NULL;
11713 xmlXPathContextPtr xpctxt = ctxt->context;
11714
11715#ifdef LIBXML_XPTR_ENABLED
11716 /*
11717 * URGENT TODO: Check the following:
11718 * We don't expect location sets if evaluating prediates, right?
11719 * Only filters should expect location sets, right?
11720 */
11721#endif /* LIBXML_XPTR_ENABLED */
11722
11723 /*
11724 * Save old context.
11725 */
11726 oldContextNode = xpctxt->node;
11727 oldContextDoc = xpctxt->doc;
11728 /*
11729 * Get the expression of this predicate.
11730 */
11731 exprOp = &ctxt->comp->steps[op->ch2];
11732 for (i = 0; i < set->nodeNr; i++) {
11733 if (set->nodeTab[i] == NULL)
11734 continue;
11735
11736 contextNode = set->nodeTab[i];
11737 xpctxt->node = contextNode;
11738 xpctxt->contextSize = contextSize;
11739 xpctxt->proximityPosition = ++contextPos;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011740
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011741 /*
11742 * Initialize the new set.
11743 * Also set the xpath document in case things like
11744 * key() evaluation are attempted on the predicate
11745 */
11746 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11747 (contextNode->doc != NULL))
11748 xpctxt->doc = contextNode->doc;
11749 /*
11750 * Evaluate the predicate expression with 1 context node
11751 * at a time; this node is packaged into a node set; this
11752 * node set is handed over to the evaluation mechanism.
11753 */
11754 if (contextObj == NULL)
11755 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11756 else
11757 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11758 contextNode);
11759
11760 valuePush(ctxt, contextObj);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011761 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011762
William M. Brackf1794562007-08-23 12:58:13 +000011763 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11764 xmlXPathObjectPtr tmp;
Daniel Veillarddf83c172010-11-17 14:12:14 +010011765 /* pop the result if any */
William M. Brackf1794562007-08-23 12:58:13 +000011766 tmp = valuePop(ctxt);
Daniel Veillardfec31bc2010-11-18 11:07:24 +010011767 if (tmp != contextObj) {
Daniel Veillarddf83c172010-11-17 14:12:14 +010011768 /*
11769 * Free up the result
11770 * then pop off contextObj, which will be freed later
11771 */
11772 xmlXPathReleaseObject(xpctxt, tmp);
11773 valuePop(ctxt);
Daniel Veillardfec31bc2010-11-18 11:07:24 +010011774 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011775 goto evaluation_error;
William M. Brackf1794562007-08-23 12:58:13 +000011776 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011777
11778 if (res)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011779 pos++;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011780
11781 if (res && (pos >= minPos) && (pos <= maxPos)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011782 /*
11783 * Fits in the requested range.
11784 */
11785 newContextSize++;
11786 if (minPos == maxPos) {
11787 /*
11788 * Only 1 node was requested.
11789 */
11790 if (contextNode->type == XML_NAMESPACE_DECL) {
11791 /*
11792 * As always: take care of those nasty
11793 * namespace nodes.
11794 */
11795 set->nodeTab[i] = NULL;
11796 }
11797 xmlXPathNodeSetClear(set, hasNsNodes);
11798 set->nodeNr = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011799 set->nodeTab[0] = contextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011800 goto evaluation_exit;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011801 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011802 if (pos == maxPos) {
11803 /*
11804 * We are done.
11805 */
11806 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11807 goto evaluation_exit;
11808 }
11809 } else {
11810 /*
11811 * Remove the entry from the initial node set.
11812 */
11813 set->nodeTab[i] = NULL;
11814 if (contextNode->type == XML_NAMESPACE_DECL)
11815 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11816 }
11817 if (exprRes != NULL) {
11818 xmlXPathReleaseObject(ctxt->context, exprRes);
11819 exprRes = NULL;
11820 }
11821 if (ctxt->value == contextObj) {
11822 /*
11823 * Don't free the temporary XPath object holding the
11824 * context node, in order to avoid massive recreation
11825 * inside this loop.
11826 */
11827 valuePop(ctxt);
11828 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11829 } else {
11830 /*
11831 * The object was lost in the evaluation machinery.
11832 * Can this happen? Maybe in case of internal-errors.
11833 */
11834 contextObj = NULL;
11835 }
11836 }
11837 goto evaluation_exit;
11838
11839evaluation_error:
11840 xmlXPathNodeSetClear(set, hasNsNodes);
11841 newContextSize = 0;
11842
11843evaluation_exit:
11844 if (contextObj != NULL) {
11845 if (ctxt->value == contextObj)
11846 valuePop(ctxt);
11847 xmlXPathReleaseObject(xpctxt, contextObj);
11848 }
11849 if (exprRes != NULL)
11850 xmlXPathReleaseObject(ctxt->context, exprRes);
11851 /*
11852 * Reset/invalidate the context.
11853 */
11854 xpctxt->node = oldContextNode;
11855 xpctxt->doc = oldContextDoc;
11856 xpctxt->contextSize = -1;
11857 xpctxt->proximityPosition = -1;
11858 return(newContextSize);
11859 }
11860 return(contextSize);
11861}
11862
11863static int
11864xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
Daniel Veillard45490ae2008-07-29 09:13:19 +000011865 xmlXPathStepOpPtr op,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011866 int *maxPos)
11867{
11868
11869 xmlXPathStepOpPtr exprOp;
11870
11871 /*
11872 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11873 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000011874
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011875 /*
11876 * If not -1, then ch1 will point to:
11877 * 1) For predicates (XPATH_OP_PREDICATE):
11878 * - an inner predicate operator
11879 * 2) For filters (XPATH_OP_FILTER):
11880 * - an inner filter operater OR
11881 * - an expression selecting the node set.
11882 * E.g. "key('a', 'b')" or "(//foo | //bar)".
Daniel Veillard45490ae2008-07-29 09:13:19 +000011883 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011884 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11885 return(0);
11886
11887 if (op->ch2 != -1) {
11888 exprOp = &ctxt->comp->steps[op->ch2];
Daniel Veillard45490ae2008-07-29 09:13:19 +000011889 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011890 return(0);
11891
11892 if ((exprOp != NULL) &&
11893 (exprOp->op == XPATH_OP_VALUE) &&
11894 (exprOp->value4 != NULL) &&
11895 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11896 {
11897 /*
11898 * We have a "[n]" predicate here.
11899 * TODO: Unfortunately this simplistic test here is not
11900 * able to detect a position() predicate in compound
11901 * expressions like "[@attr = 'a" and position() = 1],
11902 * and even not the usage of position() in
11903 * "[position() = 1]"; thus - obviously - a position-range,
11904 * like it "[position() < 5]", is also not detected.
11905 * Maybe we could rewrite the AST to ease the optimization.
11906 */
11907 *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011908
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011909 if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
11910 (float) *maxPos)
Daniel Veillard45490ae2008-07-29 09:13:19 +000011911 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011912 return(1);
11913 }
11914 }
11915 return(0);
11916}
11917
11918static int
11919xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11920 xmlXPathStepOpPtr op,
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011921 xmlNodePtr * first, xmlNodePtr * last,
11922 int toBool)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011923{
11924
11925#define XP_TEST_HIT \
11926 if (hasAxisRange != 0) { \
11927 if (++pos == maxPos) { \
11928 addNode(seq, cur); \
11929 goto axis_range_end; } \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011930 } else { \
11931 addNode(seq, cur); \
11932 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011933
11934#define XP_TEST_HIT_NS \
11935 if (hasAxisRange != 0) { \
11936 if (++pos == maxPos) { \
11937 hasNsNodes = 1; \
11938 xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
11939 goto axis_range_end; } \
11940 } else { \
11941 hasNsNodes = 1; \
11942 xmlXPathNodeSetAddNs(seq, \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011943 xpctxt->node, (xmlNsPtr) cur); \
11944 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011945
11946 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11947 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11948 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11949 const xmlChar *prefix = op->value4;
11950 const xmlChar *name = op->value5;
11951 const xmlChar *URI = NULL;
11952
11953#ifdef DEBUG_STEP
11954 int nbMatches = 0, prevMatches = 0;
11955#endif
11956 int total = 0, hasNsNodes = 0;
11957 /* The popped object holding the context nodes */
11958 xmlXPathObjectPtr obj;
11959 /* The set of context nodes for the node tests */
11960 xmlNodeSetPtr contextSeq;
11961 int contextIdx;
11962 xmlNodePtr contextNode;
11963 /* The context node for a compound traversal */
11964 xmlNodePtr outerContextNode;
11965 /* The final resulting node set wrt to all context nodes */
11966 xmlNodeSetPtr outSeq;
11967 /*
11968 * The temporary resulting node set wrt 1 context node.
11969 * Used to feed predicate evaluation.
11970 */
11971 xmlNodeSetPtr seq;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011972 xmlNodePtr cur;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011973 /* First predicate operator */
11974 xmlXPathStepOpPtr predOp;
11975 int maxPos; /* The requested position() (when a "[n]" predicate) */
11976 int hasPredicateRange, hasAxisRange, pos, size, newSize;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011977 int breakOnFirstHit;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011978
11979 xmlXPathTraversalFunction next = NULL;
11980 /* compound axis traversal */
11981 xmlXPathTraversalFunctionExt outerNext = NULL;
11982 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
11983 xmlXPathNodeSetMergeFunction mergeAndClear;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011984 xmlNodePtr oldContextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011985 xmlXPathContextPtr xpctxt = ctxt->context;
11986
11987
11988 CHECK_TYPE0(XPATH_NODESET);
11989 obj = valuePop(ctxt);
11990 /*
11991 * Setup namespaces.
11992 */
11993 if (prefix != NULL) {
11994 URI = xmlXPathNsLookup(xpctxt, prefix);
11995 if (URI == NULL) {
11996 xmlXPathReleaseObject(xpctxt, obj);
11997 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11998 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000011999 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012000 /*
12001 * Setup axis.
12002 *
12003 * MAYBE FUTURE TODO: merging optimizations:
12004 * - If the nodes to be traversed wrt to the initial nodes and
12005 * the current axis cannot overlap, then we could avoid searching
12006 * for duplicates during the merge.
12007 * But the question is how/when to evaluate if they cannot overlap.
12008 * Example: if we know that for two initial nodes, the one is
12009 * not in the ancestor-or-self axis of the other, then we could safely
12010 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12011 * the descendant-or-self axis.
12012 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012013 mergeAndClear = xmlXPathNodeSetMergeAndClear;
12014 switch (axis) {
12015 case AXIS_ANCESTOR:
12016 first = NULL;
12017 next = xmlXPathNextAncestor;
12018 break;
12019 case AXIS_ANCESTOR_OR_SELF:
12020 first = NULL;
12021 next = xmlXPathNextAncestorOrSelf;
12022 break;
12023 case AXIS_ATTRIBUTE:
12024 first = NULL;
12025 last = NULL;
12026 next = xmlXPathNextAttribute;
12027 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12028 break;
12029 case AXIS_CHILD:
12030 last = NULL;
12031 if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
12032 /*
12033 * This iterator will give us only nodes which can
12034 * hold element nodes.
12035 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000012036 outerNext = xmlXPathNextDescendantOrSelfElemParent;
12037 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012038 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12039 (type == NODE_TYPE_NODE))
12040 {
12041 /*
12042 * Optimization if an element node type is 'element'.
12043 */
12044 next = xmlXPathNextChildElement;
12045 } else
12046 next = xmlXPathNextChild;
12047 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12048 break;
12049 case AXIS_DESCENDANT:
12050 last = NULL;
12051 next = xmlXPathNextDescendant;
12052 break;
12053 case AXIS_DESCENDANT_OR_SELF:
12054 last = NULL;
12055 next = xmlXPathNextDescendantOrSelf;
12056 break;
12057 case AXIS_FOLLOWING:
12058 last = NULL;
12059 next = xmlXPathNextFollowing;
12060 break;
12061 case AXIS_FOLLOWING_SIBLING:
12062 last = NULL;
12063 next = xmlXPathNextFollowingSibling;
12064 break;
12065 case AXIS_NAMESPACE:
12066 first = NULL;
12067 last = NULL;
12068 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12069 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12070 break;
12071 case AXIS_PARENT:
12072 first = NULL;
12073 next = xmlXPathNextParent;
12074 break;
12075 case AXIS_PRECEDING:
12076 first = NULL;
12077 next = xmlXPathNextPrecedingInternal;
12078 break;
12079 case AXIS_PRECEDING_SIBLING:
12080 first = NULL;
12081 next = xmlXPathNextPrecedingSibling;
12082 break;
12083 case AXIS_SELF:
12084 first = NULL;
12085 last = NULL;
12086 next = xmlXPathNextSelf;
12087 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12088 break;
12089 }
12090
12091#ifdef DEBUG_STEP
Daniel Veillard074f37e2008-09-01 13:38:22 +000012092 xmlXPathDebugDumpStepAxis(op,
12093 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012094#endif
12095
12096 if (next == NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000012097 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012098 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012099 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012100 contextSeq = obj->nodesetval;
12101 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12102 xmlXPathReleaseObject(xpctxt, obj);
12103 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12104 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012105 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012106 /*
12107 * Predicate optimization ---------------------------------------------
12108 * If this step has a last predicate, which contains a position(),
12109 * then we'll optimize (although not exactly "position()", but only
12110 * the short-hand form, i.e., "[n]".
12111 *
12112 * Example - expression "/foo[parent::bar][1]":
Daniel Veillard45490ae2008-07-29 09:13:19 +000012113 *
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012114 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12115 * ROOT -- op->ch1
12116 * PREDICATE -- op->ch2 (predOp)
12117 * PREDICATE -- predOp->ch1 = [parent::bar]
12118 * SORT
12119 * COLLECT 'parent' 'name' 'node' bar
12120 * NODE
12121 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12122 *
12123 */
12124 maxPos = 0;
12125 predOp = NULL;
12126 hasPredicateRange = 0;
12127 hasAxisRange = 0;
12128 if (op->ch2 != -1) {
12129 /*
12130 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12131 */
12132 predOp = &ctxt->comp->steps[op->ch2];
12133 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12134 if (predOp->ch1 != -1) {
12135 /*
12136 * Use the next inner predicate operator.
12137 */
12138 predOp = &ctxt->comp->steps[predOp->ch1];
12139 hasPredicateRange = 1;
12140 } else {
12141 /*
12142 * There's no other predicate than the [n] predicate.
12143 */
12144 predOp = NULL;
12145 hasAxisRange = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012146 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012147 }
12148 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012149 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012150 /*
12151 * Axis traversal -----------------------------------------------------
12152 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012153 /*
12154 * 2.3 Node Tests
Daniel Veillard45490ae2008-07-29 09:13:19 +000012155 * - For the attribute axis, the principal node type is attribute.
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012156 * - For the namespace axis, the principal node type is namespace.
12157 * - For other axes, the principal node type is element.
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012158 *
12159 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012160 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012161 * select all element children of the context node
12162 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012163 oldContextNode = xpctxt->node;
12164 addNode = xmlXPathNodeSetAddUnique;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012165 outSeq = NULL;
12166 seq = NULL;
12167 outerContextNode = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012168 contextNode = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012169 contextIdx = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012170
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012171
12172 while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
12173 if (outerNext != NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012174 /*
12175 * This is a compound traversal.
12176 */
12177 if (contextNode == NULL) {
12178 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012179 * Set the context for the outer traversal.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012180 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012181 outerContextNode = contextSeq->nodeTab[contextIdx++];
12182 contextNode = outerNext(NULL, outerContextNode);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012183 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012184 contextNode = outerNext(contextNode, outerContextNode);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012185 if (contextNode == NULL)
12186 continue;
12187 /*
12188 * Set the context for the main traversal.
12189 */
12190 xpctxt->node = contextNode;
12191 } else
Daniel Veillard45490ae2008-07-29 09:13:19 +000012192 xpctxt->node = contextSeq->nodeTab[contextIdx++];
12193
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012194 if (seq == NULL) {
12195 seq = xmlXPathNodeSetCreate(NULL);
12196 if (seq == NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012197 total = 0;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012198 goto error;
12199 }
12200 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012201 /*
12202 * Traverse the axis and test the nodes.
12203 */
12204 pos = 0;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012205 cur = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012206 hasNsNodes = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012207 do {
12208 cur = next(ctxt, cur);
12209 if (cur == NULL)
12210 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012211
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012212 /*
12213 * QUESTION TODO: What does the "first" and "last" stuff do?
12214 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012215 if ((first != NULL) && (*first != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012216 if (*first == cur)
12217 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012218 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012219#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012220 (xmlXPathCmpNodesExt(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012221#else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012222 (xmlXPathCmpNodes(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012223#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012224 {
12225 break;
12226 }
12227 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012228 if ((last != NULL) && (*last != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012229 if (*last == cur)
12230 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012231 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012232#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012233 (xmlXPathCmpNodesExt(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012234#else
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012235 (xmlXPathCmpNodes(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012236#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012237 {
12238 break;
12239 }
12240 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012241
12242 total++;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012243
Daniel Veillardf06307e2001-07-03 10:35:50 +000012244#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012245 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12246#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +000012247
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012248 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012249 case NODE_TEST_NONE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012250 total = 0;
12251 STRANGE
12252 goto error;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012253 case NODE_TEST_TYPE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012254 /*
12255 * TODO: Don't we need to use
12256 * xmlXPathNodeSetAddNs() for namespace nodes here?
12257 * Surprisingly, some c14n tests fail, if we do this.
12258 */
12259 if (type == NODE_TYPE_NODE) {
12260 switch (cur->type) {
12261 case XML_DOCUMENT_NODE:
12262 case XML_HTML_DOCUMENT_NODE:
12263#ifdef LIBXML_DOCB_ENABLED
12264 case XML_DOCB_DOCUMENT_NODE:
12265#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +000012266 case XML_ELEMENT_NODE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012267 case XML_ATTRIBUTE_NODE:
12268 case XML_PI_NODE:
12269 case XML_COMMENT_NODE:
12270 case XML_CDATA_SECTION_NODE:
12271 case XML_TEXT_NODE:
12272 case XML_NAMESPACE_DECL:
12273 XP_TEST_HIT
12274 break;
12275 default:
12276 break;
12277 }
12278 } else if (cur->type == type) {
Kasimier T. Buchcik889b7622006-07-03 11:44:13 +000012279 if (type == XML_NAMESPACE_DECL)
12280 XP_TEST_HIT_NS
12281 else
12282 XP_TEST_HIT
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012283 } else if ((type == NODE_TYPE_TEXT) &&
12284 (cur->type == XML_CDATA_SECTION_NODE))
12285 {
12286 XP_TEST_HIT
12287 }
12288 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012289 case NODE_TEST_PI:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012290 if ((cur->type == XML_PI_NODE) &&
12291 ((name == NULL) || xmlStrEqual(name, cur->name)))
12292 {
12293 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012294 }
12295 break;
12296 case NODE_TEST_ALL:
12297 if (axis == AXIS_ATTRIBUTE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012298 if (cur->type == XML_ATTRIBUTE_NODE)
12299 {
12300 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012301 }
12302 } else if (axis == AXIS_NAMESPACE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012303 if (cur->type == XML_NAMESPACE_DECL)
12304 {
12305 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012306 }
12307 } else {
12308 if (cur->type == XML_ELEMENT_NODE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012309 if (prefix == NULL)
12310 {
12311 XP_TEST_HIT
12312
Daniel Veillardf06307e2001-07-03 10:35:50 +000012313 } else if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012314 (xmlStrEqual(URI, cur->ns->href)))
12315 {
12316 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012317 }
12318 }
12319 }
12320 break;
12321 case NODE_TEST_NS:{
12322 TODO;
12323 break;
12324 }
12325 case NODE_TEST_NAME:
Daniel Veillardfe3970e2006-11-23 16:08:30 +000012326 if (axis == AXIS_ATTRIBUTE) {
12327 if (cur->type != XML_ATTRIBUTE_NODE)
12328 break;
12329 } else if (axis == AXIS_NAMESPACE) {
12330 if (cur->type != XML_NAMESPACE_DECL)
12331 break;
12332 } else {
12333 if (cur->type != XML_ELEMENT_NODE)
12334 break;
12335 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012336 switch (cur->type) {
12337 case XML_ELEMENT_NODE:
12338 if (xmlStrEqual(name, cur->name)) {
12339 if (prefix == NULL) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012340 if (cur->ns == NULL)
12341 {
12342 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012343 }
12344 } else {
12345 if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012346 (xmlStrEqual(URI, cur->ns->href)))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012347 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012348 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012349 }
12350 }
12351 }
12352 break;
12353 case XML_ATTRIBUTE_NODE:{
12354 xmlAttrPtr attr = (xmlAttrPtr) cur;
12355
12356 if (xmlStrEqual(name, attr->name)) {
12357 if (prefix == NULL) {
12358 if ((attr->ns == NULL) ||
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012359 (attr->ns->prefix == NULL))
12360 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012361 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012362 }
12363 } else {
12364 if ((attr->ns != NULL) &&
12365 (xmlStrEqual(URI,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012366 attr->ns->href)))
12367 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012368 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012369 }
12370 }
12371 }
12372 break;
12373 }
12374 case XML_NAMESPACE_DECL:
12375 if (cur->type == XML_NAMESPACE_DECL) {
12376 xmlNsPtr ns = (xmlNsPtr) cur;
12377
12378 if ((ns->prefix != NULL) && (name != NULL)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012379 && (xmlStrEqual(ns->prefix, name)))
12380 {
12381 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012382 }
12383 }
12384 break;
12385 default:
12386 break;
12387 }
12388 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012389 } /* switch(test) */
12390 } while (cur != NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012391
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012392 goto apply_predicates;
12393
Daniel Veillard45490ae2008-07-29 09:13:19 +000012394axis_range_end: /* ----------------------------------------------------- */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012395 /*
12396 * We have a "/foo[n]", and position() = n was reached.
12397 * Note that we can have as well "/foo/::parent::foo[1]", so
12398 * a duplicate-aware merge is still needed.
12399 * Merge with the result.
12400 */
12401 if (outSeq == NULL) {
12402 outSeq = seq;
12403 seq = NULL;
12404 } else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012405 outSeq = mergeAndClear(outSeq, seq, 0);
12406 /*
12407 * Break if only a true/false result was requested.
12408 */
12409 if (toBool)
12410 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012411 continue;
12412
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012413first_hit: /* ---------------------------------------------------------- */
12414 /*
12415 * Break if only a true/false result was requested and
12416 * no predicates existed and a node test succeeded.
12417 */
12418 if (outSeq == NULL) {
12419 outSeq = seq;
12420 seq = NULL;
12421 } else
12422 outSeq = mergeAndClear(outSeq, seq, 0);
12423 break;
12424
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012425#ifdef DEBUG_STEP
12426 if (seq != NULL)
12427 nbMatches += seq->nodeNr;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012428#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012429
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012430apply_predicates: /* --------------------------------------------------- */
12431 /*
12432 * Apply predicates.
Daniel Veillard45490ae2008-07-29 09:13:19 +000012433 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012434 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12435 /*
12436 * E.g. when we have a "/foo[some expression][n]".
Daniel Veillard45490ae2008-07-29 09:13:19 +000012437 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012438 /*
12439 * QUESTION TODO: The old predicate evaluation took into
12440 * account location-sets.
12441 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12442 * Do we expect such a set here?
12443 * All what I learned now from the evaluation semantics
12444 * does not indicate that a location-set will be processed
12445 * here, so this looks OK.
Daniel Veillard45490ae2008-07-29 09:13:19 +000012446 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012447 /*
12448 * Iterate over all predicates, starting with the outermost
12449 * predicate.
12450 * TODO: Problem: we cannot execute the inner predicates first
12451 * since we cannot go back *up* the operator tree!
12452 * Options we have:
12453 * 1) Use of recursive functions (like is it currently done
12454 * via xmlXPathCompOpEval())
12455 * 2) Add a predicate evaluation information stack to the
12456 * context struct
12457 * 3) Change the way the operators are linked; we need a
12458 * "parent" field on xmlXPathStepOp
12459 *
12460 * For the moment, I'll try to solve this with a recursive
12461 * function: xmlXPathCompOpEvalPredicate().
Daniel Veillard45490ae2008-07-29 09:13:19 +000012462 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012463 size = seq->nodeNr;
12464 if (hasPredicateRange != 0)
12465 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12466 predOp, seq, size, maxPos, maxPos, hasNsNodes);
12467 else
12468 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12469 predOp, seq, size, hasNsNodes);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012470
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012471 if (ctxt->error != XPATH_EXPRESSION_OK) {
12472 total = 0;
12473 goto error;
12474 }
12475 /*
12476 * Add the filtered set of nodes to the result node set.
12477 */
12478 if (newSize == 0) {
12479 /*
12480 * The predicates filtered all nodes out.
12481 */
12482 xmlXPathNodeSetClear(seq, hasNsNodes);
12483 } else if (seq->nodeNr > 0) {
12484 /*
12485 * Add to result set.
12486 */
12487 if (outSeq == NULL) {
12488 if (size != newSize) {
12489 /*
12490 * We need to merge and clear here, since
12491 * the sequence will contained NULLed entries.
12492 */
12493 outSeq = mergeAndClear(NULL, seq, 1);
12494 } else {
12495 outSeq = seq;
12496 seq = NULL;
12497 }
12498 } else
12499 outSeq = mergeAndClear(outSeq, seq,
12500 (size != newSize) ? 1: 0);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012501 /*
12502 * Break if only a true/false result was requested.
12503 */
12504 if (toBool)
12505 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012506 }
12507 } else if (seq->nodeNr > 0) {
12508 /*
12509 * Add to result set.
12510 */
12511 if (outSeq == NULL) {
12512 outSeq = seq;
12513 seq = NULL;
12514 } else {
12515 outSeq = mergeAndClear(outSeq, seq, 0);
12516 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012517 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012518 }
12519
12520error:
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012521 if ((obj->boolval) && (obj->user != NULL)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012522 /*
12523 * QUESTION TODO: What does this do and why?
12524 * TODO: Do we have to do this also for the "error"
12525 * cleanup further down?
12526 */
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012527 ctxt->value->boolval = 1;
12528 ctxt->value->user = obj->user;
12529 obj->user = NULL;
12530 obj->boolval = 0;
12531 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012532 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012533
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012534 /*
12535 * Ensure we return at least an emtpy set.
12536 */
12537 if (outSeq == NULL) {
12538 if ((seq != NULL) && (seq->nodeNr == 0))
12539 outSeq = seq;
12540 else
12541 outSeq = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +000012542 /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012543 }
12544 if ((seq != NULL) && (seq != outSeq)) {
12545 xmlXPathFreeNodeSet(seq);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012546 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012547 /*
12548 * Hand over the result. Better to push the set also in
12549 * case of errors.
12550 */
12551 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12552 /*
12553 * Reset the context node.
12554 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012555 xpctxt->node = oldContextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012556
12557#ifdef DEBUG_STEP
12558 xmlGenericError(xmlGenericErrorContext,
12559 "\nExamined %d nodes, found %d nodes at that step\n",
12560 total, nbMatches);
12561#endif
12562
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012563 return(total);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012564}
12565
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012566static int
12567xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12568 xmlXPathStepOpPtr op, xmlNodePtr * first);
12569
Daniel Veillardf06307e2001-07-03 10:35:50 +000012570/**
12571 * xmlXPathCompOpEvalFirst:
12572 * @ctxt: the XPath parser context with the compiled expression
12573 * @op: an XPath compiled operation
12574 * @first: the first elem found so far
12575 *
12576 * Evaluate the Precompiled XPath operation searching only the first
12577 * element in document order
12578 *
12579 * Returns the number of examined objects.
12580 */
12581static int
12582xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12583 xmlXPathStepOpPtr op, xmlNodePtr * first)
12584{
12585 int total = 0, cur;
12586 xmlXPathCompExprPtr comp;
12587 xmlXPathObjectPtr arg1, arg2;
12588
Daniel Veillard556c6682001-10-06 09:59:51 +000012589 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012590 comp = ctxt->comp;
12591 switch (op->op) {
12592 case XPATH_OP_END:
12593 return (0);
12594 case XPATH_OP_UNION:
12595 total =
12596 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12597 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012598 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012599 if ((ctxt->value != NULL)
12600 && (ctxt->value->type == XPATH_NODESET)
12601 && (ctxt->value->nodesetval != NULL)
12602 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12603 /*
12604 * limit tree traversing to first node in the result
12605 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012606 /*
12607 * OPTIMIZE TODO: This implicitely sorts
12608 * the result, even if not needed. E.g. if the argument
12609 * of the count() function, no sorting is needed.
12610 * OPTIMIZE TODO: How do we know if the node-list wasn't
12611 * aready sorted?
12612 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012613 if (ctxt->value->nodesetval->nodeNr > 1)
12614 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012615 *first = ctxt->value->nodesetval->nodeTab[0];
12616 }
12617 cur =
12618 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12619 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012620 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012621 CHECK_TYPE0(XPATH_NODESET);
12622 arg2 = valuePop(ctxt);
12623
12624 CHECK_TYPE0(XPATH_NODESET);
12625 arg1 = valuePop(ctxt);
12626
12627 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12628 arg2->nodesetval);
12629 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012630 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012631 /* optimizer */
12632 if (total > cur)
12633 xmlXPathCompSwap(op);
12634 return (total + cur);
12635 case XPATH_OP_ROOT:
12636 xmlXPathRoot(ctxt);
12637 return (0);
12638 case XPATH_OP_NODE:
12639 if (op->ch1 != -1)
12640 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012641 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012642 if (op->ch2 != -1)
12643 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012644 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012645 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12646 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012647 return (total);
12648 case XPATH_OP_RESET:
12649 if (op->ch1 != -1)
12650 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012651 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012652 if (op->ch2 != -1)
12653 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012654 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012655 ctxt->context->node = NULL;
12656 return (total);
12657 case XPATH_OP_COLLECT:{
12658 if (op->ch1 == -1)
12659 return (total);
12660
12661 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012662 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012663
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012664 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012665 return (total);
12666 }
12667 case XPATH_OP_VALUE:
12668 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012669 xmlXPathCacheObjectCopy(ctxt->context,
12670 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012671 return (0);
12672 case XPATH_OP_SORT:
12673 if (op->ch1 != -1)
12674 total +=
12675 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12676 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012677 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012678 if ((ctxt->value != NULL)
12679 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012680 && (ctxt->value->nodesetval != NULL)
12681 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012682 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12683 return (total);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012684#ifdef XP_OPTIMIZED_FILTER_FIRST
12685 case XPATH_OP_FILTER:
Marius Wachtler2ddecc22010-10-12 09:09:07 +020012686 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012687 return (total);
12688#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000012689 default:
12690 return (xmlXPathCompOpEval(ctxt, op));
12691 }
12692}
12693
12694/**
12695 * xmlXPathCompOpEvalLast:
12696 * @ctxt: the XPath parser context with the compiled expression
12697 * @op: an XPath compiled operation
12698 * @last: the last elem found so far
12699 *
12700 * Evaluate the Precompiled XPath operation searching only the last
12701 * element in document order
12702 *
William M. Brack08171912003-12-29 02:52:11 +000012703 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000012704 */
12705static int
12706xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12707 xmlNodePtr * last)
12708{
12709 int total = 0, cur;
12710 xmlXPathCompExprPtr comp;
12711 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +000012712 xmlNodePtr bak;
12713 xmlDocPtr bakd;
12714 int pp;
12715 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012716
Daniel Veillard556c6682001-10-06 09:59:51 +000012717 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012718 comp = ctxt->comp;
12719 switch (op->op) {
12720 case XPATH_OP_END:
12721 return (0);
12722 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +000012723 bakd = ctxt->context->doc;
12724 bak = ctxt->context->node;
12725 pp = ctxt->context->proximityPosition;
12726 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012727 total =
12728 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
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)
12732 && (ctxt->value->nodesetval != NULL)
12733 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12734 /*
12735 * limit tree traversing to first node in the result
12736 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012737 if (ctxt->value->nodesetval->nodeNr > 1)
12738 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012739 *last =
12740 ctxt->value->nodesetval->nodeTab[ctxt->value->
12741 nodesetval->nodeNr -
12742 1];
12743 }
William M. Brackce4fc562004-01-22 02:47:18 +000012744 ctxt->context->doc = bakd;
12745 ctxt->context->node = bak;
12746 ctxt->context->proximityPosition = pp;
12747 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012748 cur =
12749 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012750 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012751 if ((ctxt->value != NULL)
12752 && (ctxt->value->type == XPATH_NODESET)
12753 && (ctxt->value->nodesetval != NULL)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012754 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012755 }
12756 CHECK_TYPE0(XPATH_NODESET);
12757 arg2 = valuePop(ctxt);
12758
12759 CHECK_TYPE0(XPATH_NODESET);
12760 arg1 = valuePop(ctxt);
12761
12762 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12763 arg2->nodesetval);
12764 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012765 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012766 /* optimizer */
12767 if (total > cur)
12768 xmlXPathCompSwap(op);
12769 return (total + cur);
12770 case XPATH_OP_ROOT:
12771 xmlXPathRoot(ctxt);
12772 return (0);
12773 case XPATH_OP_NODE:
12774 if (op->ch1 != -1)
12775 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012776 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012777 if (op->ch2 != -1)
12778 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012779 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012780 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12781 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012782 return (total);
12783 case XPATH_OP_RESET:
12784 if (op->ch1 != -1)
12785 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012786 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012787 if (op->ch2 != -1)
12788 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012789 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012790 ctxt->context->node = NULL;
12791 return (total);
12792 case XPATH_OP_COLLECT:{
12793 if (op->ch1 == -1)
12794 return (0);
12795
12796 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012797 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012798
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012799 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012800 return (total);
12801 }
12802 case XPATH_OP_VALUE:
12803 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012804 xmlXPathCacheObjectCopy(ctxt->context,
12805 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012806 return (0);
12807 case XPATH_OP_SORT:
12808 if (op->ch1 != -1)
12809 total +=
12810 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12811 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012812 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012813 if ((ctxt->value != NULL)
12814 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012815 && (ctxt->value->nodesetval != NULL)
12816 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012817 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12818 return (total);
12819 default:
12820 return (xmlXPathCompOpEval(ctxt, op));
12821 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012822}
12823
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012824#ifdef XP_OPTIMIZED_FILTER_FIRST
12825static int
12826xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12827 xmlXPathStepOpPtr op, xmlNodePtr * first)
12828{
12829 int total = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012830 xmlXPathCompExprPtr comp;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012831 xmlXPathObjectPtr res;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012832 xmlXPathObjectPtr obj;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012833 xmlNodeSetPtr oldset;
12834 xmlNodePtr oldnode;
12835 xmlDocPtr oldDoc;
12836 int i;
12837
12838 CHECK_ERROR0;
12839 comp = ctxt->comp;
12840 /*
12841 * Optimization for ()[last()] selection i.e. the last elem
12842 */
12843 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12844 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12845 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12846 int f = comp->steps[op->ch2].ch1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012847
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012848 if ((f != -1) &&
12849 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12850 (comp->steps[f].value5 == NULL) &&
12851 (comp->steps[f].value == 0) &&
12852 (comp->steps[f].value4 != NULL) &&
12853 (xmlStrEqual
12854 (comp->steps[f].value4, BAD_CAST "last"))) {
12855 xmlNodePtr last = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012856
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012857 total +=
12858 xmlXPathCompOpEvalLast(ctxt,
12859 &comp->steps[op->ch1],
12860 &last);
12861 CHECK_ERROR0;
12862 /*
12863 * The nodeset should be in document order,
12864 * Keep only the last value
12865 */
12866 if ((ctxt->value != NULL) &&
12867 (ctxt->value->type == XPATH_NODESET) &&
12868 (ctxt->value->nodesetval != NULL) &&
12869 (ctxt->value->nodesetval->nodeTab != NULL) &&
12870 (ctxt->value->nodesetval->nodeNr > 1)) {
12871 ctxt->value->nodesetval->nodeTab[0] =
12872 ctxt->value->nodesetval->nodeTab[ctxt->
12873 value->
12874 nodesetval->
12875 nodeNr -
12876 1];
12877 ctxt->value->nodesetval->nodeNr = 1;
12878 *first = *(ctxt->value->nodesetval->nodeTab);
12879 }
12880 return (total);
12881 }
12882 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012883
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012884 if (op->ch1 != -1)
12885 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12886 CHECK_ERROR0;
12887 if (op->ch2 == -1)
12888 return (total);
12889 if (ctxt->value == NULL)
12890 return (total);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012891
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012892#ifdef LIBXML_XPTR_ENABLED
12893 oldnode = ctxt->context->node;
12894 /*
12895 * Hum are we filtering the result of an XPointer expression
12896 */
12897 if (ctxt->value->type == XPATH_LOCATIONSET) {
12898 xmlXPathObjectPtr tmp = NULL;
12899 xmlLocationSetPtr newlocset = NULL;
12900 xmlLocationSetPtr oldlocset;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012901
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012902 /*
12903 * Extract the old locset, and then evaluate the result of the
12904 * expression for all the element in the locset. use it to grow
12905 * up a new locset.
12906 */
12907 CHECK_TYPE0(XPATH_LOCATIONSET);
12908 obj = valuePop(ctxt);
12909 oldlocset = obj->user;
12910 ctxt->context->node = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012911
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012912 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12913 ctxt->context->contextSize = 0;
12914 ctxt->context->proximityPosition = 0;
12915 if (op->ch2 != -1)
12916 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12917 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012918 if (res != NULL) {
12919 xmlXPathReleaseObject(ctxt->context, res);
12920 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012921 valuePush(ctxt, obj);
12922 CHECK_ERROR0;
12923 return (total);
12924 }
12925 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012926
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012927 for (i = 0; i < oldlocset->locNr; i++) {
12928 /*
12929 * Run the evaluation with a node list made of a
12930 * single item in the nodelocset.
12931 */
12932 ctxt->context->node = oldlocset->locTab[i]->user;
12933 ctxt->context->contextSize = oldlocset->locNr;
12934 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012935 if (tmp == NULL) {
12936 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12937 ctxt->context->node);
12938 } else {
12939 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12940 ctxt->context->node);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012941 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012942 valuePush(ctxt, tmp);
12943 if (op->ch2 != -1)
12944 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12945 if (ctxt->error != XPATH_EXPRESSION_OK) {
12946 xmlXPathFreeObject(obj);
12947 return(0);
12948 }
12949 /*
12950 * The result of the evaluation need to be tested to
12951 * decided whether the filter succeeded or not
12952 */
12953 res = valuePop(ctxt);
12954 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12955 xmlXPtrLocationSetAdd(newlocset,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012956 xmlXPathCacheObjectCopy(ctxt->context,
12957 oldlocset->locTab[i]));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012958 }
12959 /*
12960 * Cleanup
12961 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012962 if (res != NULL) {
12963 xmlXPathReleaseObject(ctxt->context, res);
12964 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012965 if (ctxt->value == tmp) {
12966 valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012967 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012968 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012969 * REVISIT TODO: Don't create a temporary nodeset
12970 * for everly iteration.
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012971 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012972 /* OLD: xmlXPathFreeObject(res); */
12973 } else
Daniel Veillard45490ae2008-07-29 09:13:19 +000012974 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012975 ctxt->context->node = NULL;
12976 /*
12977 * Only put the first node in the result, then leave.
12978 */
12979 if (newlocset->locNr > 0) {
12980 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
12981 break;
12982 }
12983 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012984 if (tmp != NULL) {
12985 xmlXPathReleaseObject(ctxt->context, tmp);
12986 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012987 /*
12988 * The result is used as the new evaluation locset.
12989 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012990 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012991 ctxt->context->node = NULL;
12992 ctxt->context->contextSize = -1;
12993 ctxt->context->proximityPosition = -1;
12994 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12995 ctxt->context->node = oldnode;
12996 return (total);
12997 }
12998#endif /* LIBXML_XPTR_ENABLED */
Daniel Veillard45490ae2008-07-29 09:13:19 +000012999
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013000 /*
13001 * Extract the old set, and then evaluate the result of the
13002 * expression for all the element in the set. use it to grow
13003 * up a new set.
13004 */
13005 CHECK_TYPE0(XPATH_NODESET);
13006 obj = valuePop(ctxt);
13007 oldset = obj->nodesetval;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013008
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013009 oldnode = ctxt->context->node;
13010 oldDoc = ctxt->context->doc;
13011 ctxt->context->node = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013012
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013013 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13014 ctxt->context->contextSize = 0;
13015 ctxt->context->proximityPosition = 0;
13016 /* QUESTION TODO: Why was this code commented out?
13017 if (op->ch2 != -1)
13018 total +=
13019 xmlXPathCompOpEval(ctxt,
13020 &comp->steps[op->ch2]);
13021 CHECK_ERROR0;
13022 res = valuePop(ctxt);
13023 if (res != NULL)
13024 xmlXPathFreeObject(res);
13025 */
13026 valuePush(ctxt, obj);
13027 ctxt->context->node = oldnode;
13028 CHECK_ERROR0;
13029 } else {
13030 xmlNodeSetPtr newset;
13031 xmlXPathObjectPtr tmp = NULL;
13032 /*
13033 * Initialize the new set.
13034 * Also set the xpath document in case things like
13035 * key() evaluation are attempted on the predicate
Daniel Veillard45490ae2008-07-29 09:13:19 +000013036 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013037 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +000013038 /* XXX what if xmlXPathNodeSetCreate returned NULL? */
Daniel Veillard45490ae2008-07-29 09:13:19 +000013039
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013040 for (i = 0; i < oldset->nodeNr; i++) {
13041 /*
13042 * Run the evaluation with a node list made of
13043 * a single item in the nodeset.
13044 */
13045 ctxt->context->node = oldset->nodeTab[i];
13046 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13047 (oldset->nodeTab[i]->doc != NULL))
13048 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013049 if (tmp == NULL) {
13050 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13051 ctxt->context->node);
13052 } else {
13053 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13054 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013055 }
13056 valuePush(ctxt, tmp);
13057 ctxt->context->contextSize = oldset->nodeNr;
13058 ctxt->context->proximityPosition = i + 1;
13059 if (op->ch2 != -1)
13060 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13061 if (ctxt->error != XPATH_EXPRESSION_OK) {
13062 xmlXPathFreeNodeSet(newset);
13063 xmlXPathFreeObject(obj);
13064 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013065 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013066 /*
13067 * The result of the evaluation needs to be tested to
13068 * decide whether the filter succeeded or not
13069 */
13070 res = valuePop(ctxt);
13071 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13072 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013073 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013074 /*
13075 * Cleanup
13076 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013077 if (res != NULL) {
13078 xmlXPathReleaseObject(ctxt->context, res);
13079 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013080 if (ctxt->value == tmp) {
13081 valuePop(ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013082 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013083 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013084 * in order to avoid massive recreation inside this
13085 * loop.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013086 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000013087 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013088 } else
13089 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013090 ctxt->context->node = NULL;
13091 /*
13092 * Only put the first node in the result, then leave.
13093 */
13094 if (newset->nodeNr > 0) {
13095 *first = *(newset->nodeTab);
13096 break;
13097 }
13098 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013099 if (tmp != NULL) {
13100 xmlXPathReleaseObject(ctxt->context, tmp);
13101 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013102 /*
13103 * The result is used as the new evaluation set.
13104 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013105 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013106 ctxt->context->node = NULL;
13107 ctxt->context->contextSize = -1;
13108 ctxt->context->proximityPosition = -1;
13109 /* may want to move this past the '}' later */
13110 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013111 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013112 }
13113 ctxt->context->node = oldnode;
13114 return(total);
13115}
13116#endif /* XP_OPTIMIZED_FILTER_FIRST */
13117
Owen Taylor3473f882001-02-23 17:55:21 +000013118/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013119 * xmlXPathCompOpEval:
13120 * @ctxt: the XPath parser context with the compiled expression
13121 * @op: an XPath compiled operation
13122 *
13123 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000013124 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013125 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013126static int
13127xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13128{
13129 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013130 int equal, ret;
13131 xmlXPathCompExprPtr comp;
13132 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013133 xmlNodePtr bak;
13134 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000013135 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000013136 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013137
Daniel Veillard556c6682001-10-06 09:59:51 +000013138 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013139 comp = ctxt->comp;
13140 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013141 case XPATH_OP_END:
13142 return (0);
13143 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013144 bakd = ctxt->context->doc;
13145 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013146 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013147 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013148 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013149 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013150 xmlXPathBooleanFunction(ctxt, 1);
13151 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13152 return (total);
13153 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013154 ctxt->context->doc = bakd;
13155 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013156 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013157 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013158 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013159 if (ctxt->error) {
13160 xmlXPathFreeObject(arg2);
13161 return(0);
13162 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013163 xmlXPathBooleanFunction(ctxt, 1);
13164 arg1 = valuePop(ctxt);
13165 arg1->boolval &= arg2->boolval;
13166 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013167 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013168 return (total);
13169 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013170 bakd = ctxt->context->doc;
13171 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013172 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013173 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013174 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013175 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013176 xmlXPathBooleanFunction(ctxt, 1);
13177 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13178 return (total);
13179 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013180 ctxt->context->doc = bakd;
13181 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013182 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013183 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013184 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013185 if (ctxt->error) {
13186 xmlXPathFreeObject(arg2);
13187 return(0);
13188 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013189 xmlXPathBooleanFunction(ctxt, 1);
13190 arg1 = valuePop(ctxt);
13191 arg1->boolval |= arg2->boolval;
13192 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013193 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013194 return (total);
13195 case XPATH_OP_EQUAL:
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 Veillard7089d6b2002-03-29 17:28:10 +000013202 ctxt->context->doc = bakd;
13203 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013204 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013205 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013206 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013207 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000013208 if (op->value)
Daniel Veillard45490ae2008-07-29 09:13:19 +000013209 equal = xmlXPathEqualValues(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +000013210 else
13211 equal = xmlXPathNotEqualValues(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013212 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013213 return (total);
13214 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013215 bakd = ctxt->context->doc;
13216 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013217 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013218 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013219 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013220 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013221 ctxt->context->doc = bakd;
13222 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013223 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013224 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013225 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013226 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013227 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013228 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013229 return (total);
13230 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013231 bakd = ctxt->context->doc;
13232 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013233 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013234 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013235 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013236 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013237 if (op->ch2 != -1) {
13238 ctxt->context->doc = bakd;
13239 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013240 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013241 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013242 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013243 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013244 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013245 if (op->value == 0)
13246 xmlXPathSubValues(ctxt);
13247 else if (op->value == 1)
13248 xmlXPathAddValues(ctxt);
13249 else if (op->value == 2)
13250 xmlXPathValueFlipSign(ctxt);
13251 else if (op->value == 3) {
13252 CAST_TO_NUMBER;
13253 CHECK_TYPE0(XPATH_NUMBER);
13254 }
13255 return (total);
13256 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013257 bakd = ctxt->context->doc;
13258 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013259 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013260 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013261 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013262 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013263 ctxt->context->doc = bakd;
13264 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013265 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013266 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013267 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013268 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013269 if (op->value == 0)
13270 xmlXPathMultValues(ctxt);
13271 else if (op->value == 1)
13272 xmlXPathDivValues(ctxt);
13273 else if (op->value == 2)
13274 xmlXPathModValues(ctxt);
13275 return (total);
13276 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013277 bakd = ctxt->context->doc;
13278 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013279 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013280 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013281 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013282 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013283 ctxt->context->doc = bakd;
13284 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013285 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013286 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013287 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013288 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013289 CHECK_TYPE0(XPATH_NODESET);
13290 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013291
Daniel Veillardf06307e2001-07-03 10:35:50 +000013292 CHECK_TYPE0(XPATH_NODESET);
13293 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013294
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013295 if ((arg1->nodesetval == NULL) ||
13296 ((arg2->nodesetval != NULL) &&
13297 (arg2->nodesetval->nodeNr != 0)))
13298 {
13299 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13300 arg2->nodesetval);
13301 }
13302
Daniel Veillardf06307e2001-07-03 10:35:50 +000013303 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013304 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013305 return (total);
13306 case XPATH_OP_ROOT:
13307 xmlXPathRoot(ctxt);
13308 return (total);
13309 case XPATH_OP_NODE:
13310 if (op->ch1 != -1)
13311 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013312 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013313 if (op->ch2 != -1)
13314 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013315 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013316 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13317 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013318 return (total);
13319 case XPATH_OP_RESET:
13320 if (op->ch1 != -1)
13321 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013322 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013323 if (op->ch2 != -1)
13324 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013325 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013326 ctxt->context->node = NULL;
13327 return (total);
13328 case XPATH_OP_COLLECT:{
13329 if (op->ch1 == -1)
13330 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000013331
Daniel Veillardf06307e2001-07-03 10:35:50 +000013332 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013333 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013334
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013335 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013336 return (total);
13337 }
13338 case XPATH_OP_VALUE:
13339 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013340 xmlXPathCacheObjectCopy(ctxt->context,
13341 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013342 return (total);
13343 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000013344 xmlXPathObjectPtr val;
13345
Daniel Veillardf06307e2001-07-03 10:35:50 +000013346 if (op->ch1 != -1)
13347 total +=
13348 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013349 if (op->value5 == NULL) {
13350 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13351 if (val == NULL) {
13352 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13353 return(0);
13354 }
13355 valuePush(ctxt, val);
13356 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013357 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013358
Daniel Veillardf06307e2001-07-03 10:35:50 +000013359 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13360 if (URI == NULL) {
13361 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013362 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13363 (char *) op->value4, (char *)op->value5);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013364 return (total);
13365 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013366 val = xmlXPathVariableLookupNS(ctxt->context,
13367 op->value4, URI);
13368 if (val == NULL) {
13369 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13370 return(0);
13371 }
13372 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013373 }
13374 return (total);
13375 }
13376 case XPATH_OP_FUNCTION:{
13377 xmlXPathFunction func;
13378 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000013379 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013380
13381 if (op->ch1 != -1)
13382 total +=
13383 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013384 if (ctxt->valueNr < op->value) {
13385 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013386 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013387 ctxt->error = XPATH_INVALID_OPERAND;
13388 return (total);
13389 }
13390 for (i = 0; i < op->value; i++)
13391 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13392 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013393 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013394 ctxt->error = XPATH_INVALID_OPERAND;
13395 return (total);
13396 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013397 if (op->cache != NULL)
William M. Brackad0e67c2004-12-01 14:35:10 +000013398 XML_CAST_FPTR(func) = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013399 else {
13400 const xmlChar *URI = NULL;
13401
13402 if (op->value5 == NULL)
13403 func =
13404 xmlXPathFunctionLookup(ctxt->context,
13405 op->value4);
13406 else {
13407 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13408 if (URI == NULL) {
13409 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013410 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13411 (char *)op->value4, (char *)op->value5);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013412 return (total);
13413 }
13414 func = xmlXPathFunctionLookupNS(ctxt->context,
13415 op->value4, URI);
13416 }
13417 if (func == NULL) {
13418 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013419 "xmlXPathCompOpEval: function %s not found\n",
13420 (char *)op->value4);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013421 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013422 }
William M. Brackad0e67c2004-12-01 14:35:10 +000013423 op->cache = XML_CAST_FPTR(func);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013424 op->cacheURI = (void *) URI;
13425 }
13426 oldFunc = ctxt->context->function;
13427 oldFuncURI = ctxt->context->functionURI;
13428 ctxt->context->function = op->value4;
13429 ctxt->context->functionURI = op->cacheURI;
13430 func(ctxt, op->value);
13431 ctxt->context->function = oldFunc;
13432 ctxt->context->functionURI = oldFuncURI;
13433 return (total);
13434 }
13435 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000013436 bakd = ctxt->context->doc;
13437 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000013438 pp = ctxt->context->proximityPosition;
13439 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013440 if (op->ch1 != -1)
13441 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
William M. Brack645a9242004-11-09 12:20:42 +000013442 ctxt->context->contextSize = cs;
13443 ctxt->context->proximityPosition = pp;
Daniel Veillard088bf112002-05-14 11:03:59 +000013444 ctxt->context->node = bak;
William M. Brack645a9242004-11-09 12:20:42 +000013445 ctxt->context->doc = bakd;
Daniel Veillard556c6682001-10-06 09:59:51 +000013446 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000013447 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013448 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000013449 ctxt->context->doc = bakd;
13450 ctxt->context->node = bak;
13451 CHECK_ERROR0;
13452 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013453 return (total);
13454 case XPATH_OP_PREDICATE:
13455 case XPATH_OP_FILTER:{
13456 xmlXPathObjectPtr res;
13457 xmlXPathObjectPtr obj, tmp;
13458 xmlNodeSetPtr newset = NULL;
13459 xmlNodeSetPtr oldset;
13460 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000013461 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013462 int i;
13463
13464 /*
13465 * Optimization for ()[1] selection i.e. the first elem
13466 */
13467 if ((op->ch1 != -1) && (op->ch2 != -1) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013468#ifdef XP_OPTIMIZED_FILTER_FIRST
13469 /*
13470 * FILTER TODO: Can we assume that the inner processing
13471 * will result in an ordered list if we have an
13472 * XPATH_OP_FILTER?
13473 * What about an additional field or flag on
13474 * xmlXPathObject like @sorted ? This way we wouln'd need
13475 * to assume anything, so it would be more robust and
13476 * easier to optimize.
13477 */
13478 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13479 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13480#else
13481 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13482#endif
13483 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013484 xmlXPathObjectPtr val;
13485
13486 val = comp->steps[op->ch2].value4;
13487 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13488 (val->floatval == 1.0)) {
13489 xmlNodePtr first = NULL;
13490
13491 total +=
13492 xmlXPathCompOpEvalFirst(ctxt,
13493 &comp->steps[op->ch1],
13494 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000013495 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013496 /*
13497 * The nodeset should be in document order,
13498 * Keep only the first value
13499 */
13500 if ((ctxt->value != NULL) &&
13501 (ctxt->value->type == XPATH_NODESET) &&
13502 (ctxt->value->nodesetval != NULL) &&
13503 (ctxt->value->nodesetval->nodeNr > 1))
13504 ctxt->value->nodesetval->nodeNr = 1;
13505 return (total);
13506 }
13507 }
13508 /*
13509 * Optimization for ()[last()] selection i.e. the last elem
13510 */
13511 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13512 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13513 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13514 int f = comp->steps[op->ch2].ch1;
13515
13516 if ((f != -1) &&
13517 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13518 (comp->steps[f].value5 == NULL) &&
13519 (comp->steps[f].value == 0) &&
13520 (comp->steps[f].value4 != NULL) &&
13521 (xmlStrEqual
13522 (comp->steps[f].value4, BAD_CAST "last"))) {
13523 xmlNodePtr last = NULL;
13524
13525 total +=
13526 xmlXPathCompOpEvalLast(ctxt,
13527 &comp->steps[op->ch1],
13528 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000013529 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013530 /*
13531 * The nodeset should be in document order,
13532 * Keep only the last value
13533 */
13534 if ((ctxt->value != NULL) &&
13535 (ctxt->value->type == XPATH_NODESET) &&
13536 (ctxt->value->nodesetval != NULL) &&
13537 (ctxt->value->nodesetval->nodeTab != NULL) &&
13538 (ctxt->value->nodesetval->nodeNr > 1)) {
13539 ctxt->value->nodesetval->nodeTab[0] =
13540 ctxt->value->nodesetval->nodeTab[ctxt->
13541 value->
13542 nodesetval->
13543 nodeNr -
13544 1];
13545 ctxt->value->nodesetval->nodeNr = 1;
13546 }
13547 return (total);
13548 }
13549 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013550 /*
13551 * Process inner predicates first.
13552 * Example "index[parent::book][1]":
13553 * ...
13554 * PREDICATE <-- we are here "[1]"
13555 * PREDICATE <-- process "[parent::book]" first
13556 * SORT
13557 * COLLECT 'parent' 'name' 'node' book
13558 * NODE
13559 * ELEM Object is a number : 1
13560 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013561 if (op->ch1 != -1)
13562 total +=
13563 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013564 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013565 if (op->ch2 == -1)
13566 return (total);
13567 if (ctxt->value == NULL)
13568 return (total);
13569
13570 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013571
13572#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013573 /*
13574 * Hum are we filtering the result of an XPointer expression
13575 */
13576 if (ctxt->value->type == XPATH_LOCATIONSET) {
13577 xmlLocationSetPtr newlocset = NULL;
13578 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013579
Daniel Veillardf06307e2001-07-03 10:35:50 +000013580 /*
13581 * Extract the old locset, and then evaluate the result of the
13582 * expression for all the element in the locset. use it to grow
13583 * up a new locset.
13584 */
13585 CHECK_TYPE0(XPATH_LOCATIONSET);
13586 obj = valuePop(ctxt);
13587 oldlocset = obj->user;
13588 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013589
Daniel Veillardf06307e2001-07-03 10:35:50 +000013590 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13591 ctxt->context->contextSize = 0;
13592 ctxt->context->proximityPosition = 0;
13593 if (op->ch2 != -1)
13594 total +=
13595 xmlXPathCompOpEval(ctxt,
13596 &comp->steps[op->ch2]);
13597 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013598 if (res != NULL) {
13599 xmlXPathReleaseObject(ctxt->context, res);
13600 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013601 valuePush(ctxt, obj);
13602 CHECK_ERROR0;
13603 return (total);
13604 }
13605 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013606
Daniel Veillardf06307e2001-07-03 10:35:50 +000013607 for (i = 0; i < oldlocset->locNr; i++) {
13608 /*
13609 * Run the evaluation with a node list made of a
13610 * single item in the nodelocset.
13611 */
13612 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013613 ctxt->context->contextSize = oldlocset->locNr;
13614 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013615 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13616 ctxt->context->node);
William M. Brackf7eb7942003-12-31 07:59:17 +000013617 valuePush(ctxt, tmp);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013618
Daniel Veillardf06307e2001-07-03 10:35:50 +000013619 if (op->ch2 != -1)
13620 total +=
13621 xmlXPathCompOpEval(ctxt,
13622 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013623 if (ctxt->error != XPATH_EXPRESSION_OK) {
13624 xmlXPathFreeObject(obj);
13625 return(0);
13626 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013627
Daniel Veillardf06307e2001-07-03 10:35:50 +000013628 /*
13629 * The result of the evaluation need to be tested to
13630 * decided whether the filter succeeded or not
13631 */
13632 res = valuePop(ctxt);
13633 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13634 xmlXPtrLocationSetAdd(newlocset,
13635 xmlXPathObjectCopy
13636 (oldlocset->locTab[i]));
13637 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013638
Daniel Veillardf06307e2001-07-03 10:35:50 +000013639 /*
13640 * Cleanup
13641 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013642 if (res != NULL) {
13643 xmlXPathReleaseObject(ctxt->context, res);
13644 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013645 if (ctxt->value == tmp) {
13646 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013647 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013648 }
13649
13650 ctxt->context->node = NULL;
13651 }
13652
13653 /*
13654 * The result is used as the new evaluation locset.
13655 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013656 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013657 ctxt->context->node = NULL;
13658 ctxt->context->contextSize = -1;
13659 ctxt->context->proximityPosition = -1;
13660 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13661 ctxt->context->node = oldnode;
13662 return (total);
13663 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013664#endif /* LIBXML_XPTR_ENABLED */
13665
Daniel Veillardf06307e2001-07-03 10:35:50 +000013666 /*
13667 * Extract the old set, and then evaluate the result of the
13668 * expression for all the element in the set. use it to grow
13669 * up a new set.
13670 */
13671 CHECK_TYPE0(XPATH_NODESET);
13672 obj = valuePop(ctxt);
13673 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000013674
Daniel Veillardf06307e2001-07-03 10:35:50 +000013675 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000013676 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013677 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013678
Daniel Veillardf06307e2001-07-03 10:35:50 +000013679 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13680 ctxt->context->contextSize = 0;
13681 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000013682/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000013683 if (op->ch2 != -1)
13684 total +=
13685 xmlXPathCompOpEval(ctxt,
13686 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013687 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013688 res = valuePop(ctxt);
13689 if (res != NULL)
13690 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000013691*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000013692 valuePush(ctxt, obj);
13693 ctxt->context->node = oldnode;
13694 CHECK_ERROR0;
13695 } else {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013696 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013697 /*
13698 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000013699 * Also set the xpath document in case things like
13700 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000013701 */
13702 newset = xmlXPathNodeSetCreate(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013703 /*
13704 * SPEC XPath 1.0:
13705 * "For each node in the node-set to be filtered, the
13706 * PredicateExpr is evaluated with that node as the
13707 * context node, with the number of nodes in the
13708 * node-set as the context size, and with the proximity
13709 * position of the node in the node-set with respect to
13710 * the axis as the context position;"
13711 * @oldset is the node-set" to be filtered.
13712 *
13713 * SPEC XPath 1.0:
13714 * "only predicates change the context position and
13715 * context size (see [2.4 Predicates])."
13716 * Example:
13717 * node-set context pos
13718 * nA 1
13719 * nB 2
13720 * nC 3
13721 * After applying predicate [position() > 1] :
13722 * node-set context pos
13723 * nB 1
13724 * nC 2
13725 *
13726 * removed the first node in the node-set, then
Daniel Veillard45490ae2008-07-29 09:13:19 +000013727 * the context position of the
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013728 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013729 for (i = 0; i < oldset->nodeNr; i++) {
13730 /*
13731 * Run the evaluation with a node list made of
13732 * a single item in the nodeset.
13733 */
13734 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000013735 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13736 (oldset->nodeTab[i]->doc != NULL))
13737 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013738 if (tmp == NULL) {
13739 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13740 ctxt->context->node);
13741 } else {
13742 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13743 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013744 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013745 valuePush(ctxt, tmp);
13746 ctxt->context->contextSize = oldset->nodeNr;
13747 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013748 /*
13749 * Evaluate the predicate against the context node.
13750 * Can/should we optimize position() predicates
13751 * here (e.g. "[1]")?
13752 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013753 if (op->ch2 != -1)
13754 total +=
13755 xmlXPathCompOpEval(ctxt,
13756 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013757 if (ctxt->error != XPATH_EXPRESSION_OK) {
13758 xmlXPathFreeNodeSet(newset);
13759 xmlXPathFreeObject(obj);
13760 return(0);
13761 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013762
Daniel Veillardf06307e2001-07-03 10:35:50 +000013763 /*
William M. Brack08171912003-12-29 02:52:11 +000013764 * The result of the evaluation needs to be tested to
13765 * decide whether the filter succeeded or not
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013766 */
13767 /*
13768 * OPTIMIZE TODO: Can we use
13769 * xmlXPathNodeSetAdd*Unique()* instead?
13770 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013771 res = valuePop(ctxt);
13772 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13773 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13774 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013775
Daniel Veillardf06307e2001-07-03 10:35:50 +000013776 /*
13777 * Cleanup
13778 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013779 if (res != NULL) {
13780 xmlXPathReleaseObject(ctxt->context, res);
13781 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013782 if (ctxt->value == tmp) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013783 valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013784 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013785 /*
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013786 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013787 * in order to avoid massive recreation inside this
13788 * loop.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013789 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013790 } else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013791 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013792 ctxt->context->node = NULL;
13793 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013794 if (tmp != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013795 xmlXPathReleaseObject(ctxt->context, tmp);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013796 /*
13797 * The result is used as the new evaluation set.
13798 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013799 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013800 ctxt->context->node = NULL;
13801 ctxt->context->contextSize = -1;
13802 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000013803 /* may want to move this past the '}' later */
13804 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013805 valuePush(ctxt,
13806 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013807 }
13808 ctxt->context->node = oldnode;
13809 return (total);
13810 }
13811 case XPATH_OP_SORT:
13812 if (op->ch1 != -1)
13813 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013814 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013815 if ((ctxt->value != NULL) &&
13816 (ctxt->value->type == XPATH_NODESET) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013817 (ctxt->value->nodesetval != NULL) &&
13818 (ctxt->value->nodesetval->nodeNr > 1))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013819 {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013820 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013821 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013822 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013823#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013824 case XPATH_OP_RANGETO:{
13825 xmlXPathObjectPtr range;
13826 xmlXPathObjectPtr res, obj;
13827 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000013828 xmlLocationSetPtr newlocset = NULL;
13829 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013830 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000013831 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013832
Daniel Veillardf06307e2001-07-03 10:35:50 +000013833 if (op->ch1 != -1)
13834 total +=
13835 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13836 if (op->ch2 == -1)
13837 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013838
William M. Brack08171912003-12-29 02:52:11 +000013839 if (ctxt->value->type == XPATH_LOCATIONSET) {
13840 /*
13841 * Extract the old locset, and then evaluate the result of the
13842 * expression for all the element in the locset. use it to grow
13843 * up a new locset.
13844 */
13845 CHECK_TYPE0(XPATH_LOCATIONSET);
13846 obj = valuePop(ctxt);
13847 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013848
William M. Brack08171912003-12-29 02:52:11 +000013849 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000013850 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000013851 ctxt->context->contextSize = 0;
13852 ctxt->context->proximityPosition = 0;
13853 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13854 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013855 if (res != NULL) {
13856 xmlXPathReleaseObject(ctxt->context, res);
13857 }
William M. Brack08171912003-12-29 02:52:11 +000013858 valuePush(ctxt, obj);
13859 CHECK_ERROR0;
13860 return (total);
13861 }
13862 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013863
William M. Brack08171912003-12-29 02:52:11 +000013864 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013865 /*
William M. Brack08171912003-12-29 02:52:11 +000013866 * Run the evaluation with a node list made of a
13867 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000013868 */
William M. Brackf7eb7942003-12-31 07:59:17 +000013869 ctxt->context->node = oldlocset->locTab[i]->user;
13870 ctxt->context->contextSize = oldlocset->locNr;
13871 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013872 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13873 ctxt->context->node);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013874 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013875
Daniel Veillardf06307e2001-07-03 10:35:50 +000013876 if (op->ch2 != -1)
13877 total +=
13878 xmlXPathCompOpEval(ctxt,
13879 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013880 if (ctxt->error != XPATH_EXPRESSION_OK) {
13881 xmlXPathFreeObject(obj);
13882 return(0);
13883 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013884
Daniel Veillardf06307e2001-07-03 10:35:50 +000013885 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000013886 if (res->type == XPATH_LOCATIONSET) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000013887 xmlLocationSetPtr rloc =
William M. Brack72ee48d2003-12-30 08:30:19 +000013888 (xmlLocationSetPtr)res->user;
13889 for (j=0; j<rloc->locNr; j++) {
13890 range = xmlXPtrNewRange(
13891 oldlocset->locTab[i]->user,
13892 oldlocset->locTab[i]->index,
13893 rloc->locTab[j]->user2,
13894 rloc->locTab[j]->index2);
13895 if (range != NULL) {
13896 xmlXPtrLocationSetAdd(newlocset, range);
13897 }
13898 }
13899 } else {
13900 range = xmlXPtrNewRangeNodeObject(
13901 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13902 if (range != NULL) {
13903 xmlXPtrLocationSetAdd(newlocset,range);
13904 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013905 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013906
Daniel Veillardf06307e2001-07-03 10:35:50 +000013907 /*
13908 * Cleanup
13909 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013910 if (res != NULL) {
13911 xmlXPathReleaseObject(ctxt->context, res);
13912 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013913 if (ctxt->value == tmp) {
13914 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013915 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013916 }
13917
13918 ctxt->context->node = NULL;
13919 }
William M. Brack72ee48d2003-12-30 08:30:19 +000013920 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000013921 CHECK_TYPE0(XPATH_NODESET);
13922 obj = valuePop(ctxt);
13923 oldset = obj->nodesetval;
13924 ctxt->context->node = NULL;
13925
13926 newlocset = xmlXPtrLocationSetCreate(NULL);
13927
13928 if (oldset != NULL) {
13929 for (i = 0; i < oldset->nodeNr; i++) {
13930 /*
13931 * Run the evaluation with a node list made of a single item
13932 * in the nodeset.
13933 */
13934 ctxt->context->node = oldset->nodeTab[i];
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013935 /*
13936 * OPTIMIZE TODO: Avoid recreation for every iteration.
13937 */
13938 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13939 ctxt->context->node);
William M. Brack08171912003-12-29 02:52:11 +000013940 valuePush(ctxt, tmp);
13941
13942 if (op->ch2 != -1)
13943 total +=
13944 xmlXPathCompOpEval(ctxt,
13945 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013946 if (ctxt->error != XPATH_EXPRESSION_OK) {
13947 xmlXPathFreeObject(obj);
13948 return(0);
13949 }
William M. Brack08171912003-12-29 02:52:11 +000013950
William M. Brack08171912003-12-29 02:52:11 +000013951 res = valuePop(ctxt);
13952 range =
13953 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13954 res);
13955 if (range != NULL) {
13956 xmlXPtrLocationSetAdd(newlocset, range);
13957 }
13958
13959 /*
13960 * Cleanup
13961 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013962 if (res != NULL) {
13963 xmlXPathReleaseObject(ctxt->context, res);
13964 }
William M. Brack08171912003-12-29 02:52:11 +000013965 if (ctxt->value == tmp) {
13966 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013967 xmlXPathReleaseObject(ctxt->context, res);
William M. Brack08171912003-12-29 02:52:11 +000013968 }
13969
13970 ctxt->context->node = NULL;
13971 }
13972 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013973 }
13974
13975 /*
13976 * The result is used as the new evaluation set.
13977 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013978 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013979 ctxt->context->node = NULL;
13980 ctxt->context->contextSize = -1;
13981 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000013982 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013983 return (total);
13984 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013985#endif /* LIBXML_XPTR_ENABLED */
13986 }
13987 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000013988 "XPath: unknown precompiled operation %d\n", op->op);
13989 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013990}
13991
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013992/**
13993 * xmlXPathCompOpEvalToBoolean:
13994 * @ctxt: the XPath parser context
13995 *
13996 * Evaluates if the expression evaluates to true.
13997 *
13998 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13999 */
14000static int
14001xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014002 xmlXPathStepOpPtr op,
14003 int isPredicate)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014004{
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014005 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014006
14007start:
14008 /* comp = ctxt->comp; */
14009 switch (op->op) {
14010 case XPATH_OP_END:
14011 return (0);
14012 case XPATH_OP_VALUE:
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014013 resObj = (xmlXPathObjectPtr) op->value4;
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000014014 if (isPredicate)
14015 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14016 return(xmlXPathCastToBoolean(resObj));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014017 case XPATH_OP_SORT:
14018 /*
14019 * We don't need sorting for boolean results. Skip this one.
14020 */
14021 if (op->ch1 != -1) {
14022 op = &ctxt->comp->steps[op->ch1];
14023 goto start;
14024 }
14025 return(0);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014026 case XPATH_OP_COLLECT:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014027 if (op->ch1 == -1)
14028 return(0);
14029
14030 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14031 if (ctxt->error != XPATH_EXPRESSION_OK)
14032 return(-1);
14033
14034 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14035 if (ctxt->error != XPATH_EXPRESSION_OK)
14036 return(-1);
14037
14038 resObj = valuePop(ctxt);
14039 if (resObj == NULL)
14040 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014041 break;
14042 default:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014043 /*
14044 * Fallback to call xmlXPathCompOpEval().
14045 */
14046 xmlXPathCompOpEval(ctxt, op);
14047 if (ctxt->error != XPATH_EXPRESSION_OK)
14048 return(-1);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014049
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014050 resObj = valuePop(ctxt);
14051 if (resObj == NULL)
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000014052 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014053 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014054 }
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014055
14056 if (resObj) {
14057 int res;
14058
14059 if (resObj->type == XPATH_BOOLEAN) {
14060 res = resObj->boolval;
14061 } else if (isPredicate) {
14062 /*
14063 * For predicates a result of type "number" is handled
14064 * differently:
14065 * SPEC XPath 1.0:
14066 * "If the result is a number, the result will be converted
14067 * to true if the number is equal to the context position
14068 * and will be converted to false otherwise;"
14069 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000014070 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014071 } else {
14072 res = xmlXPathCastToBoolean(resObj);
14073 }
14074 xmlXPathReleaseObject(ctxt->context, resObj);
14075 return(res);
14076 }
14077
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014078 return(0);
14079}
14080
Daniel Veillard56de87e2005-02-16 00:22:29 +000014081#ifdef XPATH_STREAMING
14082/**
14083 * xmlXPathRunStreamEval:
14084 * @ctxt: the XPath parser context with the compiled expression
14085 *
14086 * Evaluate the Precompiled Streamable XPath expression in the given context.
14087 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014088static int
14089xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14090 xmlXPathObjectPtr *resultSeq, int toBool)
14091{
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014092 int max_depth, min_depth;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014093 int from_root;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014094 int ret, depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014095 int eval_all_nodes;
William M. Brack12d37ab2005-02-21 13:54:07 +000014096 xmlNodePtr cur = NULL, limit = NULL;
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014097 xmlStreamCtxtPtr patstream = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014098
14099 int nb_nodes = 0;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014100
14101 if ((ctxt == NULL) || (comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014102 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014103 max_depth = xmlPatternMaxDepth(comp);
14104 if (max_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014105 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014106 if (max_depth == -2)
14107 max_depth = 10000;
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014108 min_depth = xmlPatternMinDepth(comp);
14109 if (min_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014110 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014111 from_root = xmlPatternFromRoot(comp);
14112 if (from_root < 0)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014113 return(-1);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014114#if 0
14115 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14116#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000014117
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014118 if (! toBool) {
14119 if (resultSeq == NULL)
14120 return(-1);
14121 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14122 if (*resultSeq == NULL)
14123 return(-1);
14124 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014125
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014126 /*
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014127 * handle the special cases of "/" amd "." being matched
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014128 */
14129 if (min_depth == 0) {
14130 if (from_root) {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014131 /* Select "/" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014132 if (toBool)
14133 return(1);
14134 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14135 (xmlNodePtr) ctxt->doc);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014136 } else {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014137 /* Select "self::node()" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014138 if (toBool)
14139 return(1);
14140 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014141 }
14142 }
14143 if (max_depth == 0) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014144 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014145 }
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014146
Daniel Veillard56de87e2005-02-16 00:22:29 +000014147 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000014148 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014149 } else if (ctxt->node != NULL) {
14150 switch (ctxt->node->type) {
14151 case XML_ELEMENT_NODE:
14152 case XML_DOCUMENT_NODE:
14153 case XML_DOCUMENT_FRAG_NODE:
14154 case XML_HTML_DOCUMENT_NODE:
14155#ifdef LIBXML_DOCB_ENABLED
14156 case XML_DOCB_DOCUMENT_NODE:
14157#endif
14158 cur = ctxt->node;
14159 break;
14160 case XML_ATTRIBUTE_NODE:
14161 case XML_TEXT_NODE:
14162 case XML_CDATA_SECTION_NODE:
14163 case XML_ENTITY_REF_NODE:
14164 case XML_ENTITY_NODE:
14165 case XML_PI_NODE:
14166 case XML_COMMENT_NODE:
14167 case XML_NOTATION_NODE:
14168 case XML_DTD_NODE:
14169 case XML_DOCUMENT_TYPE_NODE:
14170 case XML_ELEMENT_DECL:
14171 case XML_ATTRIBUTE_DECL:
14172 case XML_ENTITY_DECL:
14173 case XML_NAMESPACE_DECL:
14174 case XML_XINCLUDE_START:
14175 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000014176 break;
14177 }
14178 limit = cur;
14179 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014180 if (cur == NULL) {
14181 return(0);
14182 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014183
14184 patstream = xmlPatternGetStreamCtxt(comp);
14185 if (patstream == NULL) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014186 /*
14187 * QUESTION TODO: Is this an error?
14188 */
14189 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014190 }
14191
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014192 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014193
Daniel Veillard56de87e2005-02-16 00:22:29 +000014194 if (from_root) {
14195 ret = xmlStreamPush(patstream, NULL, NULL);
14196 if (ret < 0) {
14197 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014198 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014199 goto return_1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014200 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014201 }
14202 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014203 depth = 0;
14204 goto scan_children;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014205next_node:
Daniel Veillardd3ff7ef2006-02-27 19:43:17 +000014206 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014207 nb_nodes++;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014208
14209 switch (cur->type) {
14210 case XML_ELEMENT_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014211 case XML_TEXT_NODE:
14212 case XML_CDATA_SECTION_NODE:
14213 case XML_COMMENT_NODE:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014214 case XML_PI_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014215 if (cur->type == XML_ELEMENT_NODE) {
14216 ret = xmlStreamPush(patstream, cur->name,
Daniel Veillard56de87e2005-02-16 00:22:29 +000014217 (cur->ns ? cur->ns->href : NULL));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014218 } else if (eval_all_nodes)
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014219 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14220 else
14221 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014222
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014223 if (ret < 0) {
14224 /* NOP. */
14225 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014226 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014227 goto return_1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014228 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014229 }
14230 if ((cur->children == NULL) || (depth >= max_depth)) {
14231 ret = xmlStreamPop(patstream);
14232 while (cur->next != NULL) {
14233 cur = cur->next;
14234 if ((cur->type != XML_ENTITY_DECL) &&
14235 (cur->type != XML_DTD_NODE))
14236 goto next_node;
14237 }
14238 }
14239 default:
14240 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014241 }
14242
Daniel Veillard56de87e2005-02-16 00:22:29 +000014243scan_children:
14244 if ((cur->children != NULL) && (depth < max_depth)) {
14245 /*
Daniel Veillard45490ae2008-07-29 09:13:19 +000014246 * Do not descend on entities declarations
Daniel Veillard56de87e2005-02-16 00:22:29 +000014247 */
14248 if (cur->children->type != XML_ENTITY_DECL) {
14249 cur = cur->children;
14250 depth++;
14251 /*
14252 * Skip DTDs
14253 */
14254 if (cur->type != XML_DTD_NODE)
14255 continue;
14256 }
14257 }
14258
14259 if (cur == limit)
14260 break;
14261
14262 while (cur->next != NULL) {
14263 cur = cur->next;
14264 if ((cur->type != XML_ENTITY_DECL) &&
14265 (cur->type != XML_DTD_NODE))
14266 goto next_node;
14267 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014268
Daniel Veillard56de87e2005-02-16 00:22:29 +000014269 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014270 cur = cur->parent;
14271 depth--;
14272 if ((cur == NULL) || (cur == limit))
14273 goto done;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014274 if (cur->type == XML_ELEMENT_NODE) {
14275 ret = xmlStreamPop(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014276 } else if ((eval_all_nodes) &&
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014277 ((cur->type == XML_TEXT_NODE) ||
14278 (cur->type == XML_CDATA_SECTION_NODE) ||
14279 (cur->type == XML_COMMENT_NODE) ||
14280 (cur->type == XML_PI_NODE)))
14281 {
14282 ret = xmlStreamPop(patstream);
14283 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014284 if (cur->next != NULL) {
14285 cur = cur->next;
14286 break;
14287 }
14288 } while (cur != NULL);
14289
14290 } while ((cur != NULL) && (depth >= 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014291
Daniel Veillard56de87e2005-02-16 00:22:29 +000014292done:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014293
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014294#if 0
14295 printf("stream eval: checked %d nodes selected %d\n",
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014296 nb_nodes, retObj->nodesetval->nodeNr);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014297#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014298
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014299 if (patstream)
14300 xmlFreeStreamCtxt(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014301 return(0);
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014302
14303return_1:
14304 if (patstream)
14305 xmlFreeStreamCtxt(patstream);
14306 return(1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014307}
14308#endif /* XPATH_STREAMING */
14309
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014310/**
14311 * xmlXPathRunEval:
14312 * @ctxt: the XPath parser context with the compiled expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014313 * @toBool: evaluate to a boolean result
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014314 *
14315 * Evaluate the Precompiled XPath expression in the given context.
14316 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014317static int
14318xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14319{
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014320 xmlXPathCompExprPtr comp;
14321
14322 if ((ctxt == NULL) || (ctxt->comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014323 return(-1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014324
14325 if (ctxt->valueTab == NULL) {
14326 /* Allocate the value stack */
Daniel Veillard45490ae2008-07-29 09:13:19 +000014327 ctxt->valueTab = (xmlXPathObjectPtr *)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014328 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14329 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000014330 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014331 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014332 }
14333 ctxt->valueNr = 0;
14334 ctxt->valueMax = 10;
14335 ctxt->value = NULL;
14336 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014337#ifdef XPATH_STREAMING
14338 if (ctxt->comp->stream) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014339 int res;
14340
14341 if (toBool) {
14342 /*
14343 * Evaluation to boolean result.
14344 */
14345 res = xmlXPathRunStreamEval(ctxt->context,
14346 ctxt->comp->stream, NULL, 1);
14347 if (res != -1)
14348 return(res);
14349 } else {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014350 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014351
14352 /*
14353 * Evaluation to a sequence.
14354 */
14355 res = xmlXPathRunStreamEval(ctxt->context,
14356 ctxt->comp->stream, &resObj, 0);
14357
14358 if ((res != -1) && (resObj != NULL)) {
14359 valuePush(ctxt, resObj);
14360 return(0);
14361 }
14362 if (resObj != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +000014363 xmlXPathReleaseObject(ctxt->context, resObj);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014364 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014365 /*
14366 * QUESTION TODO: This falls back to normal XPath evaluation
14367 * if res == -1. Is this intended?
14368 */
Daniel Veillard56de87e2005-02-16 00:22:29 +000014369 }
14370#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014371 comp = ctxt->comp;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014372 if (comp->last < 0) {
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014373 xmlGenericError(xmlGenericErrorContext,
14374 "xmlXPathRunEval: last is less than zero\n");
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014375 return(-1);
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014376 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014377 if (toBool)
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014378 return(xmlXPathCompOpEvalToBoolean(ctxt,
14379 &comp->steps[comp->last], 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014380 else
14381 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14382
14383 return(0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014384}
14385
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014386/************************************************************************
14387 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +000014388 * Public interfaces *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014389 * *
14390 ************************************************************************/
14391
14392/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014393 * xmlXPathEvalPredicate:
14394 * @ctxt: the XPath context
14395 * @res: the Predicate Expression evaluation result
14396 *
14397 * Evaluate a predicate result for the current node.
14398 * A PredicateExpr is evaluated by evaluating the Expr and converting
14399 * the result to a boolean. If the result is a number, the result will
14400 * be converted to true if the number is equal to the position of the
14401 * context node in the context node list (as returned by the position
14402 * function) and will be converted to false otherwise; if the result
14403 * is not a number, then the result will be converted as if by a call
Daniel Veillard45490ae2008-07-29 09:13:19 +000014404 * to the boolean function.
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014405 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014406 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014407 */
14408int
14409xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014410 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014411 switch (res->type) {
14412 case XPATH_BOOLEAN:
14413 return(res->boolval);
14414 case XPATH_NUMBER:
14415 return(res->floatval == ctxt->proximityPosition);
14416 case XPATH_NODESET:
14417 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000014418 if (res->nodesetval == NULL)
14419 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014420 return(res->nodesetval->nodeNr != 0);
14421 case XPATH_STRING:
14422 return((res->stringval != NULL) &&
14423 (xmlStrlen(res->stringval) != 0));
14424 default:
14425 STRANGE
14426 }
14427 return(0);
14428}
14429
14430/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014431 * xmlXPathEvaluatePredicateResult:
14432 * @ctxt: the XPath Parser context
14433 * @res: the Predicate Expression evaluation result
14434 *
14435 * Evaluate a predicate result for the current node.
14436 * A PredicateExpr is evaluated by evaluating the Expr and converting
14437 * the result to a boolean. If the result is a number, the result will
14438 * be converted to true if the number is equal to the position of the
14439 * context node in the context node list (as returned by the position
14440 * function) and will be converted to false otherwise; if the result
14441 * is not a number, then the result will be converted as if by a call
Daniel Veillard45490ae2008-07-29 09:13:19 +000014442 * to the boolean function.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014443 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014444 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014445 */
14446int
Daniel Veillard45490ae2008-07-29 09:13:19 +000014447xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014448 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014449 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014450 switch (res->type) {
14451 case XPATH_BOOLEAN:
14452 return(res->boolval);
14453 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000014454#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000014455 return((res->floatval == ctxt->context->proximityPosition) &&
14456 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000014457#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014458 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000014459#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014460 case XPATH_NODESET:
14461 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000014462 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000014463 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014464 return(res->nodesetval->nodeNr != 0);
14465 case XPATH_STRING:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014466 return((res->stringval != NULL) && (res->stringval[0] != 0));
William M. Brack08171912003-12-29 02:52:11 +000014467#ifdef LIBXML_XPTR_ENABLED
14468 case XPATH_LOCATIONSET:{
14469 xmlLocationSetPtr ptr = res->user;
14470 if (ptr == NULL)
14471 return(0);
14472 return (ptr->locNr != 0);
14473 }
14474#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014475 default:
14476 STRANGE
14477 }
14478 return(0);
14479}
14480
Daniel Veillard56de87e2005-02-16 00:22:29 +000014481#ifdef XPATH_STREAMING
14482/**
14483 * xmlXPathTryStreamCompile:
14484 * @ctxt: an XPath context
14485 * @str: the XPath expression
14486 *
14487 * Try to compile the XPath expression as a streamable subset.
14488 *
14489 * Returns the compiled expression or NULL if failed to compile.
14490 */
14491static xmlXPathCompExprPtr
14492xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14493 /*
14494 * Optimization: use streaming patterns when the XPath expression can
14495 * be compiled to a stream lookup
14496 */
14497 xmlPatternPtr stream;
14498 xmlXPathCompExprPtr comp;
14499 xmlDictPtr dict = NULL;
14500 const xmlChar **namespaces = NULL;
14501 xmlNsPtr ns;
14502 int i, j;
14503
14504 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14505 (!xmlStrchr(str, '@'))) {
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014506 const xmlChar *tmp;
14507
14508 /*
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014509 * We don't try to handle expressions using the verbose axis
14510 * specifiers ("::"), just the simplied form at this point.
14511 * Additionally, if there is no list of namespaces available and
14512 * there's a ":" in the expression, indicating a prefixed QName,
14513 * then we won't try to compile either. xmlPatterncompile() needs
14514 * to have a list of namespaces at compilation time in order to
14515 * compile prefixed name tests.
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014516 */
14517 tmp = xmlStrchr(str, ':');
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014518 if ((tmp != NULL) &&
14519 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
Daniel Veillard45490ae2008-07-29 09:13:19 +000014520 return(NULL);
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014521
Daniel Veillard56de87e2005-02-16 00:22:29 +000014522 if (ctxt != NULL) {
14523 dict = ctxt->dict;
14524 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000014525 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000014526 if (namespaces == NULL) {
14527 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14528 return(NULL);
14529 }
14530 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14531 ns = ctxt->namespaces[j];
14532 namespaces[i++] = ns->href;
14533 namespaces[i++] = ns->prefix;
14534 }
14535 namespaces[i++] = NULL;
Daniel Veillard13cee4e2009-09-05 14:52:55 +020014536 namespaces[i] = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014537 }
14538 }
14539
William M. Brackea152c02005-06-09 18:12:28 +000014540 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14541 &namespaces[0]);
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014542 if (namespaces != NULL) {
14543 xmlFree((xmlChar **)namespaces);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014544 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014545 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14546 comp = xmlXPathNewCompExpr();
14547 if (comp == NULL) {
14548 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14549 return(NULL);
14550 }
14551 comp->stream = stream;
14552 comp->dict = dict;
14553 if (comp->dict)
14554 xmlDictReference(comp->dict);
14555 return(comp);
14556 }
14557 xmlFreePattern(stream);
14558 }
14559 return(NULL);
14560}
14561#endif /* XPATH_STREAMING */
14562
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014563static int
14564xmlXPathCanRewriteDosExpression(xmlChar *expr)
14565{
14566 if (expr == NULL)
14567 return(0);
14568 do {
14569 if ((*expr == '/') && (*(++expr) == '/'))
14570 return(1);
14571 } while (*expr++);
14572 return(0);
14573}
14574static void
14575xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14576{
14577 /*
14578 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14579 * internal representation.
14580 */
14581 if (op->ch1 != -1) {
14582 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +000014583 ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014584 ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
14585 ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
14586 {
14587 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014588 * This is a "child::foo"
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014589 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000014590 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014591
14592 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +000014593 (prevop->ch1 != -1) &&
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014594 ((xmlXPathAxisVal) prevop->value ==
14595 AXIS_DESCENDANT_OR_SELF) &&
14596 (prevop->ch2 == -1) &&
14597 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014598 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
14599 (comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
Daniel Veillard45490ae2008-07-29 09:13:19 +000014600 {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014601 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014602 * This is a "/descendant-or-self::node()" without predicates.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014603 * Eliminate it.
14604 */
14605 op->ch1 = prevop->ch1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014606 op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014607 }
14608 }
14609 if (op->ch1 != -1)
14610 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
14611 }
14612 if (op->ch2 != -1)
14613 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
14614}
14615
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014616/**
Daniel Veillard4773df22004-01-23 13:15:13 +000014617 * xmlXPathCtxtCompile:
14618 * @ctxt: an XPath context
14619 * @str: the XPath expression
14620 *
14621 * Compile an XPath expression
14622 *
14623 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14624 * the caller has to free the object.
14625 */
14626xmlXPathCompExprPtr
14627xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14628 xmlXPathParserContextPtr pctxt;
14629 xmlXPathCompExprPtr comp;
14630
Daniel Veillard56de87e2005-02-16 00:22:29 +000014631#ifdef XPATH_STREAMING
14632 comp = xmlXPathTryStreamCompile(ctxt, str);
14633 if (comp != NULL)
14634 return(comp);
14635#endif
14636
Daniel Veillard4773df22004-01-23 13:15:13 +000014637 xmlXPathInit();
14638
14639 pctxt = xmlXPathNewParserContext(str, ctxt);
William M. Brack11be2d02007-01-24 19:17:19 +000014640 if (pctxt == NULL)
14641 return NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014642 xmlXPathCompileExpr(pctxt, 1);
Daniel Veillard4773df22004-01-23 13:15:13 +000014643
14644 if( pctxt->error != XPATH_EXPRESSION_OK )
14645 {
14646 xmlXPathFreeParserContext(pctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000014647 return(NULL);
Daniel Veillard4773df22004-01-23 13:15:13 +000014648 }
14649
14650 if (*pctxt->cur != 0) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014651 /*
Daniel Veillard4773df22004-01-23 13:15:13 +000014652 * aleksey: in some cases this line prints *second* error message
14653 * (see bug #78858) and probably this should be fixed.
14654 * However, we are not sure that all error messages are printed
14655 * out in other places. It's not critical so we leave it as-is for now
14656 */
14657 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14658 comp = NULL;
14659 } else {
14660 comp = pctxt->comp;
14661 pctxt->comp = NULL;
14662 }
14663 xmlXPathFreeParserContext(pctxt);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014664
Daniel Veillard4773df22004-01-23 13:15:13 +000014665 if (comp != NULL) {
14666 comp->expr = xmlStrdup(str);
14667#ifdef DEBUG_EVAL_COUNTS
14668 comp->string = xmlStrdup(str);
14669 comp->nb = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014670#endif
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014671 if ((comp->expr != NULL) &&
14672 (comp->nbStep > 2) &&
14673 (comp->last >= 0) &&
Kasimier T. Buchcik7cb3fa92006-06-06 15:27:46 +000014674 (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
14675 {
14676 xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014677 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014678 }
Daniel Veillard4773df22004-01-23 13:15:13 +000014679 return(comp);
14680}
14681
14682/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014683 * xmlXPathCompile:
14684 * @str: the XPath expression
14685 *
14686 * Compile an XPath expression
14687 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000014688 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014689 * the caller has to free the object.
14690 */
14691xmlXPathCompExprPtr
14692xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000014693 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014694}
14695
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014696/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014697 * xmlXPathCompiledEvalInternal:
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014698 * @comp: the compiled XPath expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014699 * @ctxt: the XPath context
14700 * @resObj: the resulting XPath object or NULL
14701 * @toBool: 1 if only a boolean result is requested
Owen Taylor3473f882001-02-23 17:55:21 +000014702 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014703 * Evaluate the Precompiled XPath expression in the given context.
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014704 * The caller has to free @resObj.
Owen Taylor3473f882001-02-23 17:55:21 +000014705 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014706 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000014707 * the caller has to free the object.
14708 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014709static int
14710xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14711 xmlXPathContextPtr ctxt,
14712 xmlXPathObjectPtr *resObj,
14713 int toBool)
14714{
Daniel Veillard45490ae2008-07-29 09:13:19 +000014715 xmlXPathParserContextPtr pctxt;
Daniel Veillard81463942001-10-16 12:34:39 +000014716#ifndef LIBXML_THREAD_ENABLED
14717 static int reentance = 0;
14718#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014719 int res;
Owen Taylor3473f882001-02-23 17:55:21 +000014720
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014721 CHECK_CTXT_NEG(ctxt)
William M. Brackf13f77f2004-11-12 16:03:48 +000014722
14723 if (comp == NULL)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014724 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +000014725 xmlXPathInit();
14726
Daniel Veillard81463942001-10-16 12:34:39 +000014727#ifndef LIBXML_THREAD_ENABLED
14728 reentance++;
14729 if (reentance > 1)
14730 xmlXPathDisableOptimizer = 1;
14731#endif
14732
Daniel Veillardf06307e2001-07-03 10:35:50 +000014733#ifdef DEBUG_EVAL_COUNTS
14734 comp->nb++;
14735 if ((comp->string != NULL) && (comp->nb > 100)) {
14736 fprintf(stderr, "100 x %s\n", comp->string);
14737 comp->nb = 0;
14738 }
14739#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014740 pctxt = xmlXPathCompParserContext(comp, ctxt);
14741 res = xmlXPathRunEval(pctxt, toBool);
Owen Taylor3473f882001-02-23 17:55:21 +000014742
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014743 if (resObj) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014744 if (pctxt->value == NULL) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014745 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014746 "xmlXPathCompiledEval: evaluation failed\n");
Daniel Veillard45490ae2008-07-29 09:13:19 +000014747 *resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014748 } else {
14749 *resObj = valuePop(pctxt);
14750 }
Owen Taylor3473f882001-02-23 17:55:21 +000014751 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014752
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014753 /*
14754 * Pop all remaining objects from the stack.
14755 */
14756 if (pctxt->valueNr > 0) {
14757 xmlXPathObjectPtr tmp;
14758 int stack = 0;
14759
14760 do {
14761 tmp = valuePop(pctxt);
14762 if (tmp != NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014763 stack++;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014764 xmlXPathReleaseObject(ctxt, tmp);
14765 }
14766 } while (tmp != NULL);
14767 if ((stack != 0) &&
14768 ((toBool) || ((resObj) && (*resObj))))
14769 {
14770 xmlGenericError(xmlGenericErrorContext,
14771 "xmlXPathCompiledEval: %d objects left on the stack.\n",
14772 stack);
14773 }
Owen Taylor3473f882001-02-23 17:55:21 +000014774 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014775
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014776 if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14777 xmlXPathFreeObject(*resObj);
14778 *resObj = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014779 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014780 pctxt->comp = NULL;
14781 xmlXPathFreeParserContext(pctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000014782#ifndef LIBXML_THREAD_ENABLED
14783 reentance--;
14784#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014785
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014786 return(res);
14787}
14788
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014789/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014790 * xmlXPathCompiledEval:
14791 * @comp: the compiled XPath expression
14792 * @ctx: the XPath context
14793 *
14794 * Evaluate the Precompiled XPath expression in the given context.
14795 *
14796 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14797 * the caller has to free the object.
14798 */
14799xmlXPathObjectPtr
14800xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14801{
14802 xmlXPathObjectPtr res = NULL;
14803
14804 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14805 return(res);
14806}
14807
14808/**
14809 * xmlXPathCompiledEvalToBoolean:
14810 * @comp: the compiled XPath expression
14811 * @ctxt: the XPath context
14812 *
14813 * Applies the XPath boolean() function on the result of the given
14814 * compiled expression.
14815 *
14816 * Returns 1 if the expression evaluated to true, 0 if to false and
14817 * -1 in API and internal errors.
14818 */
14819int
14820xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14821 xmlXPathContextPtr ctxt)
14822{
14823 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14824}
14825
14826/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014827 * xmlXPathEvalExpr:
14828 * @ctxt: the XPath Parser context
14829 *
14830 * Parse and evaluate an XPath expression in the given context,
14831 * then push the result on the context stack
14832 */
14833void
14834xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014835#ifdef XPATH_STREAMING
14836 xmlXPathCompExprPtr comp;
14837#endif
14838
Daniel Veillarda82b1822004-11-08 16:24:57 +000014839 if (ctxt == NULL) return;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014840
Daniel Veillard56de87e2005-02-16 00:22:29 +000014841#ifdef XPATH_STREAMING
14842 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14843 if (comp != NULL) {
14844 if (ctxt->comp != NULL)
14845 xmlXPathFreeCompExpr(ctxt->comp);
14846 ctxt->comp = comp;
14847 if (ctxt->cur != NULL)
14848 while (*ctxt->cur != 0) ctxt->cur++;
14849 } else
14850#endif
14851 {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014852 xmlXPathCompileExpr(ctxt, 1);
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014853 /*
14854 * In this scenario the expression string will sit in ctxt->base.
14855 */
14856 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
14857 (ctxt->comp != NULL) &&
14858 (ctxt->base != NULL) &&
Kasimier T. Buchcik7cb3fa92006-06-06 15:27:46 +000014859 (ctxt->comp->nbStep > 2) &&
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014860 (ctxt->comp->last >= 0) &&
14861 (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014862 {
14863 xmlXPathRewriteDOSExpression(ctxt->comp,
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014864 &ctxt->comp->steps[ctxt->comp->last]);
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014865 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014866 }
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000014867 CHECK_ERROR;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014868 xmlXPathRunEval(ctxt, 0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014869}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014870
14871/**
14872 * xmlXPathEval:
14873 * @str: the XPath expression
14874 * @ctx: the XPath context
14875 *
14876 * Evaluate the XPath Location Path in the given context.
14877 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014878 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014879 * the caller has to free the object.
14880 */
14881xmlXPathObjectPtr
14882xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14883 xmlXPathParserContextPtr ctxt;
14884 xmlXPathObjectPtr res, tmp, init = NULL;
14885 int stack = 0;
14886
William M. Brackf13f77f2004-11-12 16:03:48 +000014887 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014888
William M. Brackf13f77f2004-11-12 16:03:48 +000014889 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014890
14891 ctxt = xmlXPathNewParserContext(str, ctx);
William M. Brack11be2d02007-01-24 19:17:19 +000014892 if (ctxt == NULL)
14893 return NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014894 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014895
14896 if (ctxt->value == NULL) {
14897 xmlGenericError(xmlGenericErrorContext,
14898 "xmlXPathEval: evaluation failed\n");
14899 res = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014900 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
Daniel Veillard56de87e2005-02-16 00:22:29 +000014901#ifdef XPATH_STREAMING
14902 && (ctxt->comp->stream == NULL)
14903#endif
14904 ) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014905 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14906 res = NULL;
14907 } else {
14908 res = valuePop(ctxt);
14909 }
14910
14911 do {
14912 tmp = valuePop(ctxt);
14913 if (tmp != NULL) {
14914 if (tmp != init)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014915 stack++;
14916 xmlXPathReleaseObject(ctx, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014917 }
14918 } while (tmp != NULL);
14919 if ((stack != 0) && (res != NULL)) {
14920 xmlGenericError(xmlGenericErrorContext,
14921 "xmlXPathEval: %d object left on the stack\n",
14922 stack);
14923 }
14924 if (ctxt->error != XPATH_EXPRESSION_OK) {
14925 xmlXPathFreeObject(res);
14926 res = NULL;
14927 }
14928
Owen Taylor3473f882001-02-23 17:55:21 +000014929 xmlXPathFreeParserContext(ctxt);
14930 return(res);
14931}
14932
14933/**
14934 * xmlXPathEvalExpression:
14935 * @str: the XPath expression
14936 * @ctxt: the XPath context
14937 *
14938 * Evaluate the XPath expression in the given context.
14939 *
14940 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14941 * the caller has to free the object.
14942 */
14943xmlXPathObjectPtr
14944xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14945 xmlXPathParserContextPtr pctxt;
14946 xmlXPathObjectPtr res, tmp;
14947 int stack = 0;
14948
William M. Brackf13f77f2004-11-12 16:03:48 +000014949 CHECK_CTXT(ctxt)
Owen Taylor3473f882001-02-23 17:55:21 +000014950
William M. Brackf13f77f2004-11-12 16:03:48 +000014951 xmlXPathInit();
Owen Taylor3473f882001-02-23 17:55:21 +000014952
14953 pctxt = xmlXPathNewParserContext(str, ctxt);
William M. Brack11be2d02007-01-24 19:17:19 +000014954 if (pctxt == NULL)
14955 return NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000014956 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000014957
Daniel Veillardc465ffc2006-10-17 19:39:33 +000014958 if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
Owen Taylor3473f882001-02-23 17:55:21 +000014959 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14960 res = NULL;
14961 } else {
14962 res = valuePop(pctxt);
14963 }
14964 do {
14965 tmp = valuePop(pctxt);
14966 if (tmp != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014967 xmlXPathReleaseObject(ctxt, tmp);
Owen Taylor3473f882001-02-23 17:55:21 +000014968 stack++;
14969 }
14970 } while (tmp != NULL);
14971 if ((stack != 0) && (res != NULL)) {
14972 xmlGenericError(xmlGenericErrorContext,
14973 "xmlXPathEvalExpression: %d object left on the stack\n",
14974 stack);
14975 }
14976 xmlXPathFreeParserContext(pctxt);
14977 return(res);
14978}
14979
Daniel Veillard42766c02002-08-22 20:52:17 +000014980/************************************************************************
14981 * *
14982 * Extra functions not pertaining to the XPath spec *
14983 * *
14984 ************************************************************************/
14985/**
14986 * xmlXPathEscapeUriFunction:
14987 * @ctxt: the XPath Parser context
14988 * @nargs: the number of arguments
14989 *
14990 * Implement the escape-uri() XPath function
14991 * string escape-uri(string $str, bool $escape-reserved)
14992 *
14993 * This function applies the URI escaping rules defined in section 2 of [RFC
14994 * 2396] to the string supplied as $uri-part, which typically represents all
14995 * or part of a URI. The effect of the function is to replace any special
14996 * character in the string by an escape sequence of the form %xx%yy...,
14997 * where xxyy... is the hexadecimal representation of the octets used to
14998 * represent the character in UTF-8.
14999 *
15000 * The set of characters that are escaped depends on the setting of the
15001 * boolean argument $escape-reserved.
15002 *
15003 * If $escape-reserved is true, all characters are escaped other than lower
15004 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15005 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15006 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15007 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15008 * A-F).
15009 *
15010 * If $escape-reserved is false, the behavior differs in that characters
15011 * referred to in [RFC 2396] as reserved characters are not escaped. These
15012 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
Daniel Veillard45490ae2008-07-29 09:13:19 +000015013 *
Daniel Veillard42766c02002-08-22 20:52:17 +000015014 * [RFC 2396] does not define whether escaped URIs should use lower case or
15015 * upper case for hexadecimal digits. To ensure that escaped URIs can be
15016 * compared using string comparison functions, this function must always use
15017 * the upper-case letters A-F.
Daniel Veillard45490ae2008-07-29 09:13:19 +000015018 *
Daniel Veillard42766c02002-08-22 20:52:17 +000015019 * Generally, $escape-reserved should be set to true when escaping a string
15020 * that is to form a single part of a URI, and to false when escaping an
15021 * entire URI or URI reference.
Daniel Veillard45490ae2008-07-29 09:13:19 +000015022 *
15023 * In the case of non-ascii characters, the string is encoded according to
Daniel Veillard42766c02002-08-22 20:52:17 +000015024 * utf-8 and then converted according to RFC 2396.
15025 *
15026 * Examples
Daniel Veillard45490ae2008-07-29 09:13:19 +000015027 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
Daniel Veillard42766c02002-08-22 20:52:17 +000015028 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15029 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15030 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15031 *
15032 */
Daniel Veillard118aed72002-09-24 14:13:13 +000015033static void
Daniel Veillard42766c02002-08-22 20:52:17 +000015034xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15035 xmlXPathObjectPtr str;
15036 int escape_reserved;
15037 xmlBufferPtr target;
15038 xmlChar *cptr;
15039 xmlChar escape[4];
Daniel Veillard45490ae2008-07-29 09:13:19 +000015040
Daniel Veillard42766c02002-08-22 20:52:17 +000015041 CHECK_ARITY(2);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015042
Daniel Veillard42766c02002-08-22 20:52:17 +000015043 escape_reserved = xmlXPathPopBoolean(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015044
Daniel Veillard42766c02002-08-22 20:52:17 +000015045 CAST_TO_STRING;
15046 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015047
Daniel Veillard42766c02002-08-22 20:52:17 +000015048 target = xmlBufferCreate();
Daniel Veillard45490ae2008-07-29 09:13:19 +000015049
Daniel Veillard42766c02002-08-22 20:52:17 +000015050 escape[0] = '%';
15051 escape[3] = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000015052
Daniel Veillard42766c02002-08-22 20:52:17 +000015053 if (target) {
15054 for (cptr = str->stringval; *cptr; cptr++) {
15055 if ((*cptr >= 'A' && *cptr <= 'Z') ||
15056 (*cptr >= 'a' && *cptr <= 'z') ||
15057 (*cptr >= '0' && *cptr <= '9') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000015058 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
Daniel Veillard42766c02002-08-22 20:52:17 +000015059 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
15060 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000015061 (*cptr == '%' &&
Daniel Veillard42766c02002-08-22 20:52:17 +000015062 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15063 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15064 (cptr[1] >= '0' && cptr[1] <= '9')) &&
15065 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15066 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15067 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15068 (!escape_reserved &&
15069 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15070 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15071 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15072 *cptr == ','))) {
15073 xmlBufferAdd(target, cptr, 1);
15074 } else {
15075 if ((*cptr >> 4) < 10)
15076 escape[1] = '0' + (*cptr >> 4);
15077 else
15078 escape[1] = 'A' - 10 + (*cptr >> 4);
15079 if ((*cptr & 0xF) < 10)
15080 escape[2] = '0' + (*cptr & 0xF);
15081 else
15082 escape[2] = 'A' - 10 + (*cptr & 0xF);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015083
Daniel Veillard42766c02002-08-22 20:52:17 +000015084 xmlBufferAdd(target, &escape[0], 3);
15085 }
15086 }
15087 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015088 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15089 xmlBufferContent(target)));
Daniel Veillard42766c02002-08-22 20:52:17 +000015090 xmlBufferFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015091 xmlXPathReleaseObject(ctxt->context, str);
Daniel Veillard42766c02002-08-22 20:52:17 +000015092}
15093
Owen Taylor3473f882001-02-23 17:55:21 +000015094/**
15095 * xmlXPathRegisterAllFunctions:
15096 * @ctxt: the XPath context
15097 *
15098 * Registers all default XPath functions in this context
15099 */
15100void
15101xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15102{
15103 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15104 xmlXPathBooleanFunction);
15105 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15106 xmlXPathCeilingFunction);
15107 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15108 xmlXPathCountFunction);
15109 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15110 xmlXPathConcatFunction);
15111 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15112 xmlXPathContainsFunction);
15113 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15114 xmlXPathIdFunction);
15115 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15116 xmlXPathFalseFunction);
15117 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15118 xmlXPathFloorFunction);
15119 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15120 xmlXPathLastFunction);
15121 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15122 xmlXPathLangFunction);
15123 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15124 xmlXPathLocalNameFunction);
15125 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15126 xmlXPathNotFunction);
15127 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15128 xmlXPathNameFunction);
15129 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15130 xmlXPathNamespaceURIFunction);
15131 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15132 xmlXPathNormalizeFunction);
15133 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15134 xmlXPathNumberFunction);
15135 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15136 xmlXPathPositionFunction);
15137 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15138 xmlXPathRoundFunction);
15139 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15140 xmlXPathStringFunction);
15141 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15142 xmlXPathStringLengthFunction);
15143 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15144 xmlXPathStartsWithFunction);
15145 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15146 xmlXPathSubstringFunction);
15147 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15148 xmlXPathSubstringBeforeFunction);
15149 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15150 xmlXPathSubstringAfterFunction);
15151 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15152 xmlXPathSumFunction);
15153 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15154 xmlXPathTrueFunction);
15155 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15156 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000015157
15158 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15159 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15160 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000015161}
15162
15163#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000015164#define bottom_xpath
15165#include "elfgcchack.h"