blob: 57442e6a05ff98806ac9f4ed9729f40a84230db9 [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,
337 xmlXPathErrorMessages[error]);
338 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,
348 xmlXPathErrorMessages[error]);
349 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,
372 xmlXPathErrorMessages[error]);
373 }
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) {
882 fprintf(output, shift);
883 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)) {
890 fprintf(output, shift);
891 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) {
907 fprintf(output, shift);
908 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) {
930 fprintf(output, shift);
931 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++) {
939 fprintf(output, shift);
940 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)) {
956 fprintf(output, shift);
957 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
962 fprintf(output, shift);
963 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) {
977 fprintf(output, shift);
978 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++) {
984 fprintf(output, shift);
985 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 Veillard45490ae2008-07-29 09:13:19 +00001011 fprintf(output, 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");
1066 fprintf(output, shift);
1067 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");
1074 fprintf(output, shift);
1075 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);
1081 fprintf(output, shift);
1082 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
1114 fprintf(output, shift);
1115 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
1301 fprintf(output, shift);
1302
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
3525 cur->nodeMax *= 2;
3526 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3527 sizeof(xmlNodePtr));
3528 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003529 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003530 return;
3531 }
3532 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
3578 cur->nodeMax *= 2;
3579 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3580 sizeof(xmlNodePtr));
3581 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003582 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003583 return;
3584 }
3585 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
3630 cur->nodeMax *= 2;
3631 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3632 sizeof(xmlNodePtr));
3633 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003634 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003635 return;
3636 }
3637 cur->nodeTab = temp;
3638 }
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
3741 val1->nodeMax *= 2;
3742 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3743 sizeof(xmlNodePtr));
3744 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003745 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003746 return(NULL);
3747 }
3748 val1->nodeTab = temp;
3749 }
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 set1->nodeMax *= 2;
3911 temp = (xmlNodePtr *) xmlRealloc(
3912 set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3913 if (temp == NULL) {
3914 xmlXPathErrMemory(NULL, "merging nodeset\n");
3915 return(NULL);
3916 }
3917 set1->nodeTab = temp;
3918 }
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 set1->nodeMax *= 2;
3995 temp = (xmlNodePtr *) xmlRealloc(
3996 set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3997 if (temp == NULL) {
3998 xmlXPathErrMemory(NULL, "merging nodeset\n");
3999 return(NULL);
4000 }
4001 set1->nodeTab = temp;
4002 }
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
5006 * @prefix: the namespace prefix
5007 * @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);
5021
5022 if (ctxt->nsHash == NULL)
5023 ctxt->nsHash = xmlHashCreate(10);
5024 if (ctxt->nsHash == NULL)
5025 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00005026 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00005027 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00005028 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00005029 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00005030 (xmlHashDeallocator)xmlFree));
5031}
5032
5033/**
5034 * xmlXPathNsLookup:
5035 * @ctxt: the XPath context
5036 * @prefix: the namespace prefix value
5037 *
5038 * Search in the namespace declaration array of the context for the given
5039 * namespace name associated to the given prefix
5040 *
5041 * Returns the value or NULL if not found
5042 */
5043const xmlChar *
5044xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5045 if (ctxt == NULL)
5046 return(NULL);
5047 if (prefix == NULL)
5048 return(NULL);
5049
5050#ifdef XML_XML_NAMESPACE
5051 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5052 return(XML_XML_NAMESPACE);
5053#endif
5054
Daniel Veillardc8f620b2001-04-30 20:31:33 +00005055 if (ctxt->namespaces != NULL) {
5056 int i;
5057
5058 for (i = 0;i < ctxt->nsNr;i++) {
5059 if ((ctxt->namespaces[i] != NULL) &&
5060 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5061 return(ctxt->namespaces[i]->href);
5062 }
5063 }
Owen Taylor3473f882001-02-23 17:55:21 +00005064
5065 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5066}
5067
5068/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005069 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00005070 * @ctxt: the XPath context
5071 *
5072 * Cleanup the XPath context data associated to registered variables
5073 */
5074void
5075xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5076 if (ctxt == NULL)
5077 return;
5078
Daniel Veillard42766c02002-08-22 20:52:17 +00005079 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00005080 ctxt->nsHash = NULL;
5081}
5082
5083/************************************************************************
5084 * *
5085 * Routines to handle Values *
5086 * *
5087 ************************************************************************/
5088
William M. Brack08171912003-12-29 02:52:11 +00005089/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005090
5091/**
5092 * xmlXPathNewFloat:
5093 * @val: the double value
5094 *
5095 * Create a new xmlXPathObjectPtr of type double and of value @val
5096 *
5097 * Returns the newly created object.
5098 */
5099xmlXPathObjectPtr
5100xmlXPathNewFloat(double val) {
5101 xmlXPathObjectPtr ret;
5102
5103 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5104 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005105 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005106 return(NULL);
5107 }
5108 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5109 ret->type = XPATH_NUMBER;
5110 ret->floatval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005111#ifdef XP_DEBUG_OBJ_USAGE
5112 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5113#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005114 return(ret);
5115}
5116
5117/**
5118 * xmlXPathNewBoolean:
5119 * @val: the boolean value
5120 *
5121 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5122 *
5123 * Returns the newly created object.
5124 */
5125xmlXPathObjectPtr
5126xmlXPathNewBoolean(int val) {
5127 xmlXPathObjectPtr ret;
5128
5129 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5130 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005131 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005132 return(NULL);
5133 }
5134 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5135 ret->type = XPATH_BOOLEAN;
5136 ret->boolval = (val != 0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005137#ifdef XP_DEBUG_OBJ_USAGE
5138 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5139#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005140 return(ret);
5141}
5142
5143/**
5144 * xmlXPathNewString:
5145 * @val: the xmlChar * value
5146 *
5147 * Create a new xmlXPathObjectPtr of type string and of value @val
5148 *
5149 * Returns the newly created object.
5150 */
5151xmlXPathObjectPtr
5152xmlXPathNewString(const xmlChar *val) {
5153 xmlXPathObjectPtr ret;
5154
5155 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5156 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005157 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005158 return(NULL);
5159 }
5160 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5161 ret->type = XPATH_STRING;
5162 if (val != NULL)
5163 ret->stringval = xmlStrdup(val);
5164 else
5165 ret->stringval = xmlStrdup((const xmlChar *)"");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005166#ifdef XP_DEBUG_OBJ_USAGE
5167 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5168#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005169 return(ret);
5170}
5171
5172/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005173 * xmlXPathWrapString:
5174 * @val: the xmlChar * value
5175 *
5176 * Wraps the @val string into an XPath object.
5177 *
5178 * Returns the newly created object.
5179 */
5180xmlXPathObjectPtr
5181xmlXPathWrapString (xmlChar *val) {
5182 xmlXPathObjectPtr ret;
5183
5184 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5185 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005186 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005187 return(NULL);
5188 }
5189 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5190 ret->type = XPATH_STRING;
5191 ret->stringval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005192#ifdef XP_DEBUG_OBJ_USAGE
5193 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5194#endif
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005195 return(ret);
5196}
5197
5198/**
Owen Taylor3473f882001-02-23 17:55:21 +00005199 * xmlXPathNewCString:
5200 * @val: the char * value
5201 *
5202 * Create a new xmlXPathObjectPtr of type string and of value @val
5203 *
5204 * Returns the newly created object.
5205 */
5206xmlXPathObjectPtr
5207xmlXPathNewCString(const char *val) {
5208 xmlXPathObjectPtr ret;
5209
5210 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5211 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005212 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005213 return(NULL);
5214 }
5215 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5216 ret->type = XPATH_STRING;
5217 ret->stringval = xmlStrdup(BAD_CAST val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005218#ifdef XP_DEBUG_OBJ_USAGE
5219 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5220#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005221 return(ret);
5222}
5223
5224/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005225 * xmlXPathWrapCString:
5226 * @val: the char * value
5227 *
5228 * Wraps a string into an XPath object.
5229 *
5230 * Returns the newly created object.
5231 */
5232xmlXPathObjectPtr
5233xmlXPathWrapCString (char * val) {
5234 return(xmlXPathWrapString((xmlChar *)(val)));
5235}
5236
5237/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005238 * xmlXPathWrapExternal:
5239 * @val: the user data
5240 *
5241 * Wraps the @val data into an XPath object.
5242 *
5243 * Returns the newly created object.
5244 */
5245xmlXPathObjectPtr
5246xmlXPathWrapExternal (void *val) {
5247 xmlXPathObjectPtr ret;
5248
5249 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5250 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005251 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005252 return(NULL);
5253 }
5254 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5255 ret->type = XPATH_USERS;
5256 ret->user = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005257#ifdef XP_DEBUG_OBJ_USAGE
5258 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5259#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005260 return(ret);
5261}
5262
5263/**
Owen Taylor3473f882001-02-23 17:55:21 +00005264 * xmlXPathObjectCopy:
5265 * @val: the original object
5266 *
5267 * allocate a new copy of a given object
5268 *
5269 * Returns the newly created object.
5270 */
5271xmlXPathObjectPtr
5272xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5273 xmlXPathObjectPtr ret;
5274
5275 if (val == NULL)
5276 return(NULL);
5277
5278 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5279 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005280 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005281 return(NULL);
5282 }
5283 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005284#ifdef XP_DEBUG_OBJ_USAGE
5285 xmlXPathDebugObjUsageRequested(NULL, val->type);
5286#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005287 switch (val->type) {
5288 case XPATH_BOOLEAN:
5289 case XPATH_NUMBER:
5290 case XPATH_POINT:
5291 case XPATH_RANGE:
5292 break;
5293 case XPATH_STRING:
5294 ret->stringval = xmlStrdup(val->stringval);
5295 break;
5296 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00005297#if 0
5298/*
5299 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5300 this previous handling is no longer correct, and can cause some serious
5301 problems (ref. bug 145547)
5302*/
Owen Taylor3473f882001-02-23 17:55:21 +00005303 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005304 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005305 xmlNodePtr cur, tmp;
5306 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005307
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005308 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005309 top = xmlNewDoc(NULL);
5310 top->name = (char *)
5311 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005312 ret->user = top;
5313 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005314 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005315 cur = val->nodesetval->nodeTab[0]->children;
5316 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005317 tmp = xmlDocCopyNode(cur, top, 1);
5318 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005319 cur = cur->next;
5320 }
5321 }
William M. Bracke9449c52004-07-11 14:41:20 +00005322
Daniel Veillard9adc0462003-03-24 18:39:54 +00005323 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005324 } else
Owen Taylor3473f882001-02-23 17:55:21 +00005325 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005326 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00005327 break;
William M. Bracke9449c52004-07-11 14:41:20 +00005328#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005329 case XPATH_NODESET:
5330 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005331 /* Do not deallocate the copied tree value */
5332 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005333 break;
5334 case XPATH_LOCATIONSET:
5335#ifdef LIBXML_XPTR_ENABLED
5336 {
5337 xmlLocationSetPtr loc = val->user;
5338 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5339 break;
5340 }
5341#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00005342 case XPATH_USERS:
5343 ret->user = val->user;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005344 break;
Thomas Broyer47334c02001-10-07 16:41:52 +00005345 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00005346 xmlGenericError(xmlGenericErrorContext,
5347 "xmlXPathObjectCopy: unsupported type %d\n",
5348 val->type);
5349 break;
5350 }
5351 return(ret);
5352}
5353
5354/**
5355 * xmlXPathFreeObject:
5356 * @obj: the object to free
5357 *
5358 * Free up an xmlXPathObjectPtr object.
5359 */
5360void
5361xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5362 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005363 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00005364 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00005365#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005366 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005367 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00005368 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00005369 } else
5370#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005371 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
William M. Bracke9449c52004-07-11 14:41:20 +00005372 if (obj->nodesetval != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00005373 xmlXPathFreeValueTree(obj->nodesetval);
Daniel Veillard77851712001-02-27 21:54:07 +00005374 } else {
5375 if (obj->nodesetval != NULL)
5376 xmlXPathFreeNodeSet(obj->nodesetval);
5377 }
Owen Taylor3473f882001-02-23 17:55:21 +00005378#ifdef LIBXML_XPTR_ENABLED
5379 } else if (obj->type == XPATH_LOCATIONSET) {
5380 if (obj->user != NULL)
5381 xmlXPtrFreeLocationSet(obj->user);
5382#endif
5383 } else if (obj->type == XPATH_STRING) {
5384 if (obj->stringval != NULL)
5385 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005386 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005387#ifdef XP_DEBUG_OBJ_USAGE
5388 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5389#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00005390 xmlFree(obj);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005391}
Owen Taylor3473f882001-02-23 17:55:21 +00005392
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005393/**
5394 * xmlXPathReleaseObject:
5395 * @obj: the xmlXPathObjectPtr to free or to cache
5396 *
5397 * Depending on the state of the cache this frees the given
5398 * XPath object or stores it in the cache.
5399 */
5400static void
5401xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5402{
5403#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5404 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5405 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5406
5407#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5408
5409 if (obj == NULL)
5410 return;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005411 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005412 xmlXPathFreeObject(obj);
Daniel Veillard45490ae2008-07-29 09:13:19 +00005413 } else {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005414 xmlXPathContextCachePtr cache =
5415 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005416
5417 switch (obj->type) {
5418 case XPATH_NODESET:
5419 case XPATH_XSLT_TREE:
5420 if (obj->nodesetval != NULL) {
5421 if (obj->boolval) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00005422 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005423 * It looks like the @boolval is used for
5424 * evaluation if this an XSLT Result Tree Fragment.
5425 * TODO: Check if this assumption is correct.
5426 */
5427 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5428 xmlXPathFreeValueTree(obj->nodesetval);
5429 obj->nodesetval = NULL;
5430 } else if ((obj->nodesetval->nodeMax <= 40) &&
5431 (XP_CACHE_WANTS(cache->nodesetObjs,
5432 cache->maxNodeset)))
5433 {
5434 XP_CACHE_ADD(cache->nodesetObjs, obj);
5435 goto obj_cached;
5436 } else {
5437 xmlXPathFreeNodeSet(obj->nodesetval);
5438 obj->nodesetval = NULL;
5439 }
5440 }
5441 break;
5442 case XPATH_STRING:
5443 if (obj->stringval != NULL)
5444 xmlFree(obj->stringval);
5445
5446 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5447 XP_CACHE_ADD(cache->stringObjs, obj);
5448 goto obj_cached;
5449 }
5450 break;
5451 case XPATH_BOOLEAN:
5452 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5453 XP_CACHE_ADD(cache->booleanObjs, obj);
5454 goto obj_cached;
5455 }
5456 break;
5457 case XPATH_NUMBER:
5458 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5459 XP_CACHE_ADD(cache->numberObjs, obj);
5460 goto obj_cached;
5461 }
5462 break;
5463#ifdef LIBXML_XPTR_ENABLED
5464 case XPATH_LOCATIONSET:
5465 if (obj->user != NULL) {
5466 xmlXPtrFreeLocationSet(obj->user);
5467 }
5468 goto free_obj;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005469#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005470 default:
5471 goto free_obj;
5472 }
5473
5474 /*
5475 * Fallback to adding to the misc-objects slot.
5476 */
5477 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5478 XP_CACHE_ADD(cache->miscObjs, obj);
5479 } else
5480 goto free_obj;
5481
5482obj_cached:
5483
5484#ifdef XP_DEBUG_OBJ_USAGE
5485 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5486#endif
5487
5488 if (obj->nodesetval != NULL) {
5489 xmlNodeSetPtr tmpset = obj->nodesetval;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005490
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005491 /*
5492 * TODO: Due to those nasty ns-nodes, we need to traverse
5493 * the list and free the ns-nodes.
5494 * URGENT TODO: Check if it's actually slowing things down.
5495 * Maybe we shouldn't try to preserve the list.
5496 */
5497 if (tmpset->nodeNr > 1) {
5498 int i;
5499 xmlNodePtr node;
5500
5501 for (i = 0; i < tmpset->nodeNr; i++) {
5502 node = tmpset->nodeTab[i];
5503 if ((node != NULL) &&
5504 (node->type == XML_NAMESPACE_DECL))
5505 {
5506 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5507 }
5508 }
5509 } else if (tmpset->nodeNr == 1) {
5510 if ((tmpset->nodeTab[0] != NULL) &&
5511 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5512 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
Daniel Veillard45490ae2008-07-29 09:13:19 +00005513 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005514 tmpset->nodeNr = 0;
5515 memset(obj, 0, sizeof(xmlXPathObject));
5516 obj->nodesetval = tmpset;
5517 } else
5518 memset(obj, 0, sizeof(xmlXPathObject));
5519
5520 return;
5521
5522free_obj:
5523 /*
5524 * Cache is full; free the object.
Daniel Veillard45490ae2008-07-29 09:13:19 +00005525 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005526 if (obj->nodesetval != NULL)
5527 xmlXPathFreeNodeSet(obj->nodesetval);
5528#ifdef XP_DEBUG_OBJ_USAGE
5529 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5530#endif
5531 xmlFree(obj);
5532 }
5533 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005534}
5535
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005536
5537/************************************************************************
5538 * *
5539 * Type Casting Routines *
5540 * *
5541 ************************************************************************/
5542
5543/**
5544 * xmlXPathCastBooleanToString:
5545 * @val: a boolean
5546 *
5547 * Converts a boolean to its string value.
5548 *
5549 * Returns a newly allocated string.
5550 */
5551xmlChar *
5552xmlXPathCastBooleanToString (int val) {
5553 xmlChar *ret;
5554 if (val)
5555 ret = xmlStrdup((const xmlChar *) "true");
5556 else
5557 ret = xmlStrdup((const xmlChar *) "false");
5558 return(ret);
5559}
5560
5561/**
5562 * xmlXPathCastNumberToString:
5563 * @val: a number
5564 *
5565 * Converts a number to its string value.
5566 *
5567 * Returns a newly allocated string.
5568 */
5569xmlChar *
5570xmlXPathCastNumberToString (double val) {
5571 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00005572 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005573 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005574 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005575 break;
5576 case -1:
5577 ret = xmlStrdup((const xmlChar *) "-Infinity");
5578 break;
5579 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00005580 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005581 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005582 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5583 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005584 } else {
5585 /* could be improved */
5586 char buf[100];
Daniel Veillard11ce4002006-03-10 00:36:23 +00005587 xmlXPathFormatNumber(val, buf, 99);
5588 buf[99] = 0;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005589 ret = xmlStrdup((const xmlChar *) buf);
5590 }
5591 }
5592 return(ret);
5593}
5594
5595/**
5596 * xmlXPathCastNodeToString:
5597 * @node: a node
5598 *
5599 * Converts a node to its string value.
5600 *
5601 * Returns a newly allocated string.
5602 */
5603xmlChar *
5604xmlXPathCastNodeToString (xmlNodePtr node) {
William M. Brackd611c882007-05-31 05:07:17 +00005605xmlChar *ret;
5606 if ((ret = xmlNodeGetContent(node)) == NULL)
5607 ret = xmlStrdup((const xmlChar *) "");
5608 return(ret);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005609}
5610
5611/**
5612 * xmlXPathCastNodeSetToString:
5613 * @ns: a node-set
5614 *
5615 * Converts a node-set to its string value.
5616 *
5617 * Returns a newly allocated string.
5618 */
5619xmlChar *
5620xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5621 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5622 return(xmlStrdup((const xmlChar *) ""));
5623
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00005624 if (ns->nodeNr > 1)
5625 xmlXPathNodeSetSort(ns);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005626 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5627}
5628
5629/**
5630 * xmlXPathCastToString:
5631 * @val: an XPath object
5632 *
5633 * Converts an existing object to its string() equivalent
5634 *
Kasimier T. Buchcik50128ad2006-08-15 13:04:07 +00005635 * Returns the allocated string value of the object, NULL in case of error.
Daniel Veillard45490ae2008-07-29 09:13:19 +00005636 * It's up to the caller to free the string memory with xmlFree().
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005637 */
5638xmlChar *
5639xmlXPathCastToString(xmlXPathObjectPtr val) {
5640 xmlChar *ret = NULL;
5641
5642 if (val == NULL)
5643 return(xmlStrdup((const xmlChar *) ""));
5644 switch (val->type) {
5645 case XPATH_UNDEFINED:
5646#ifdef DEBUG_EXPR
5647 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5648#endif
5649 ret = xmlStrdup((const xmlChar *) "");
5650 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005651 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005652 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005653 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5654 break;
5655 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00005656 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005657 case XPATH_BOOLEAN:
5658 ret = xmlXPathCastBooleanToString(val->boolval);
5659 break;
5660 case XPATH_NUMBER: {
5661 ret = xmlXPathCastNumberToString(val->floatval);
5662 break;
5663 }
5664 case XPATH_USERS:
5665 case XPATH_POINT:
5666 case XPATH_RANGE:
5667 case XPATH_LOCATIONSET:
5668 TODO
5669 ret = xmlStrdup((const xmlChar *) "");
5670 break;
5671 }
5672 return(ret);
5673}
5674
5675/**
5676 * xmlXPathConvertString:
5677 * @val: an XPath object
5678 *
5679 * Converts an existing object to its string() equivalent
5680 *
5681 * Returns the new object, the old one is freed (or the operation
5682 * is done directly on @val)
5683 */
5684xmlXPathObjectPtr
5685xmlXPathConvertString(xmlXPathObjectPtr val) {
5686 xmlChar *res = NULL;
5687
5688 if (val == NULL)
5689 return(xmlXPathNewCString(""));
5690
5691 switch (val->type) {
5692 case XPATH_UNDEFINED:
5693#ifdef DEBUG_EXPR
5694 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5695#endif
5696 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005697 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005698 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005699 res = xmlXPathCastNodeSetToString(val->nodesetval);
5700 break;
5701 case XPATH_STRING:
5702 return(val);
5703 case XPATH_BOOLEAN:
5704 res = xmlXPathCastBooleanToString(val->boolval);
5705 break;
5706 case XPATH_NUMBER:
5707 res = xmlXPathCastNumberToString(val->floatval);
5708 break;
5709 case XPATH_USERS:
5710 case XPATH_POINT:
5711 case XPATH_RANGE:
5712 case XPATH_LOCATIONSET:
5713 TODO;
5714 break;
5715 }
5716 xmlXPathFreeObject(val);
5717 if (res == NULL)
5718 return(xmlXPathNewCString(""));
5719 return(xmlXPathWrapString(res));
5720}
5721
5722/**
5723 * xmlXPathCastBooleanToNumber:
5724 * @val: a boolean
5725 *
5726 * Converts a boolean to its number value
5727 *
5728 * Returns the number value
5729 */
5730double
5731xmlXPathCastBooleanToNumber(int val) {
5732 if (val)
5733 return(1.0);
5734 return(0.0);
5735}
5736
5737/**
5738 * xmlXPathCastStringToNumber:
5739 * @val: a string
5740 *
5741 * Converts a string to its number value
5742 *
5743 * Returns the number value
5744 */
5745double
5746xmlXPathCastStringToNumber(const xmlChar * val) {
5747 return(xmlXPathStringEvalNumber(val));
5748}
5749
5750/**
5751 * xmlXPathCastNodeToNumber:
5752 * @node: a node
5753 *
5754 * Converts a node to its number value
5755 *
5756 * Returns the number value
5757 */
5758double
5759xmlXPathCastNodeToNumber (xmlNodePtr node) {
5760 xmlChar *strval;
5761 double ret;
5762
5763 if (node == NULL)
5764 return(xmlXPathNAN);
5765 strval = xmlXPathCastNodeToString(node);
5766 if (strval == NULL)
5767 return(xmlXPathNAN);
5768 ret = xmlXPathCastStringToNumber(strval);
5769 xmlFree(strval);
5770
5771 return(ret);
5772}
5773
5774/**
5775 * xmlXPathCastNodeSetToNumber:
5776 * @ns: a node-set
5777 *
5778 * Converts a node-set to its number value
5779 *
5780 * Returns the number value
5781 */
5782double
5783xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5784 xmlChar *str;
5785 double ret;
5786
5787 if (ns == NULL)
5788 return(xmlXPathNAN);
5789 str = xmlXPathCastNodeSetToString(ns);
5790 ret = xmlXPathCastStringToNumber(str);
5791 xmlFree(str);
5792 return(ret);
5793}
5794
5795/**
5796 * xmlXPathCastToNumber:
5797 * @val: an XPath object
5798 *
5799 * Converts an XPath object to its number value
5800 *
5801 * Returns the number value
5802 */
5803double
5804xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5805 double ret = 0.0;
5806
5807 if (val == NULL)
5808 return(xmlXPathNAN);
5809 switch (val->type) {
5810 case XPATH_UNDEFINED:
5811#ifdef DEGUB_EXPR
5812 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5813#endif
5814 ret = xmlXPathNAN;
5815 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005816 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005817 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005818 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5819 break;
5820 case XPATH_STRING:
5821 ret = xmlXPathCastStringToNumber(val->stringval);
5822 break;
5823 case XPATH_NUMBER:
5824 ret = val->floatval;
5825 break;
5826 case XPATH_BOOLEAN:
5827 ret = xmlXPathCastBooleanToNumber(val->boolval);
5828 break;
5829 case XPATH_USERS:
5830 case XPATH_POINT:
5831 case XPATH_RANGE:
5832 case XPATH_LOCATIONSET:
5833 TODO;
5834 ret = xmlXPathNAN;
5835 break;
5836 }
5837 return(ret);
5838}
5839
5840/**
5841 * xmlXPathConvertNumber:
5842 * @val: an XPath object
5843 *
5844 * Converts an existing object to its number() equivalent
5845 *
5846 * Returns the new object, the old one is freed (or the operation
5847 * is done directly on @val)
5848 */
5849xmlXPathObjectPtr
5850xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5851 xmlXPathObjectPtr ret;
5852
5853 if (val == NULL)
5854 return(xmlXPathNewFloat(0.0));
5855 if (val->type == XPATH_NUMBER)
5856 return(val);
5857 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5858 xmlXPathFreeObject(val);
5859 return(ret);
5860}
5861
5862/**
5863 * xmlXPathCastNumberToBoolean:
5864 * @val: a number
5865 *
5866 * Converts a number to its boolean value
5867 *
5868 * Returns the boolean value
5869 */
5870int
5871xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00005872 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005873 return(0);
5874 return(1);
5875}
5876
5877/**
5878 * xmlXPathCastStringToBoolean:
5879 * @val: a string
5880 *
5881 * Converts a string to its boolean value
5882 *
5883 * Returns the boolean value
5884 */
5885int
5886xmlXPathCastStringToBoolean (const xmlChar *val) {
5887 if ((val == NULL) || (xmlStrlen(val) == 0))
5888 return(0);
5889 return(1);
5890}
5891
5892/**
5893 * xmlXPathCastNodeSetToBoolean:
5894 * @ns: a node-set
5895 *
5896 * Converts a node-set to its boolean value
5897 *
5898 * Returns the boolean value
5899 */
5900int
5901xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5902 if ((ns == NULL) || (ns->nodeNr == 0))
5903 return(0);
5904 return(1);
5905}
5906
5907/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005908 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005909 * @val: an XPath object
5910 *
5911 * Converts an XPath object to its boolean value
5912 *
5913 * Returns the boolean value
5914 */
5915int
5916xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5917 int ret = 0;
5918
5919 if (val == NULL)
5920 return(0);
5921 switch (val->type) {
5922 case XPATH_UNDEFINED:
5923#ifdef DEBUG_EXPR
5924 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
5925#endif
5926 ret = 0;
5927 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005928 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005929 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005930 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5931 break;
5932 case XPATH_STRING:
5933 ret = xmlXPathCastStringToBoolean(val->stringval);
5934 break;
5935 case XPATH_NUMBER:
5936 ret = xmlXPathCastNumberToBoolean(val->floatval);
5937 break;
5938 case XPATH_BOOLEAN:
5939 ret = val->boolval;
5940 break;
5941 case XPATH_USERS:
5942 case XPATH_POINT:
5943 case XPATH_RANGE:
5944 case XPATH_LOCATIONSET:
5945 TODO;
5946 ret = 0;
5947 break;
5948 }
5949 return(ret);
5950}
5951
5952
5953/**
5954 * xmlXPathConvertBoolean:
5955 * @val: an XPath object
5956 *
5957 * Converts an existing object to its boolean() equivalent
5958 *
5959 * Returns the new object, the old one is freed (or the operation
5960 * is done directly on @val)
5961 */
5962xmlXPathObjectPtr
5963xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
5964 xmlXPathObjectPtr ret;
5965
5966 if (val == NULL)
5967 return(xmlXPathNewBoolean(0));
5968 if (val->type == XPATH_BOOLEAN)
5969 return(val);
5970 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
5971 xmlXPathFreeObject(val);
5972 return(ret);
5973}
5974
Owen Taylor3473f882001-02-23 17:55:21 +00005975/************************************************************************
5976 * *
5977 * Routines to handle XPath contexts *
5978 * *
5979 ************************************************************************/
5980
5981/**
5982 * xmlXPathNewContext:
5983 * @doc: the XML document
5984 *
5985 * Create a new xmlXPathContext
5986 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00005987 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00005988 */
5989xmlXPathContextPtr
5990xmlXPathNewContext(xmlDocPtr doc) {
5991 xmlXPathContextPtr ret;
5992
5993 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
5994 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005995 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005996 return(NULL);
5997 }
5998 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
5999 ret->doc = doc;
6000 ret->node = NULL;
6001
6002 ret->varHash = NULL;
6003
6004 ret->nb_types = 0;
6005 ret->max_types = 0;
6006 ret->types = NULL;
6007
6008 ret->funcHash = xmlHashCreate(0);
6009
6010 ret->nb_axis = 0;
6011 ret->max_axis = 0;
6012 ret->axis = NULL;
6013
6014 ret->nsHash = NULL;
6015 ret->user = NULL;
6016
6017 ret->contextSize = -1;
6018 ret->proximityPosition = -1;
6019
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006020#ifdef XP_DEFAULT_CACHE_ON
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006021 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006022 xmlXPathFreeContext(ret);
6023 return(NULL);
6024 }
6025#endif
6026
Daniel Veillard45490ae2008-07-29 09:13:19 +00006027 xmlXPathRegisterAllFunctions(ret);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006028
Owen Taylor3473f882001-02-23 17:55:21 +00006029 return(ret);
6030}
6031
6032/**
6033 * xmlXPathFreeContext:
6034 * @ctxt: the context to free
6035 *
6036 * Free up an xmlXPathContext
6037 */
6038void
6039xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006040 if (ctxt == NULL) return;
6041
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006042 if (ctxt->cache != NULL)
6043 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
Owen Taylor3473f882001-02-23 17:55:21 +00006044 xmlXPathRegisteredNsCleanup(ctxt);
6045 xmlXPathRegisteredFuncsCleanup(ctxt);
6046 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006047 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00006048 xmlFree(ctxt);
6049}
6050
6051/************************************************************************
6052 * *
6053 * Routines to handle XPath parser contexts *
6054 * *
6055 ************************************************************************/
6056
6057#define CHECK_CTXT(ctxt) \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006058 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00006059 __xmlRaiseError(NULL, NULL, NULL, \
6060 NULL, NULL, XML_FROM_XPATH, \
6061 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6062 __FILE__, __LINE__, \
6063 NULL, NULL, NULL, 0, 0, \
6064 "NULL context pointer\n"); \
6065 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00006066 } \
6067
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006068#define CHECK_CTXT_NEG(ctxt) \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006069 if (ctxt == NULL) { \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006070 __xmlRaiseError(NULL, NULL, NULL, \
6071 NULL, NULL, XML_FROM_XPATH, \
6072 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6073 __FILE__, __LINE__, \
6074 NULL, NULL, NULL, 0, 0, \
6075 "NULL context pointer\n"); \
6076 return(-1); \
6077 } \
6078
Owen Taylor3473f882001-02-23 17:55:21 +00006079
6080#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00006081 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006082 (ctxt->doc->children == NULL)) { \
Daniel Veillard57b25162004-11-06 14:50:18 +00006083 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00006084 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00006085 }
Owen Taylor3473f882001-02-23 17:55:21 +00006086
6087
6088/**
6089 * xmlXPathNewParserContext:
6090 * @str: the XPath expression
6091 * @ctxt: the XPath context
6092 *
6093 * Create a new xmlXPathParserContext
6094 *
6095 * Returns the xmlXPathParserContext just allocated.
6096 */
6097xmlXPathParserContextPtr
6098xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6099 xmlXPathParserContextPtr ret;
6100
6101 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6102 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006103 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006104 return(NULL);
6105 }
6106 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6107 ret->cur = ret->base = str;
6108 ret->context = ctxt;
6109
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006110 ret->comp = xmlXPathNewCompExpr();
6111 if (ret->comp == NULL) {
6112 xmlFree(ret->valueTab);
6113 xmlFree(ret);
6114 return(NULL);
6115 }
Daniel Veillard4773df22004-01-23 13:15:13 +00006116 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6117 ret->comp->dict = ctxt->dict;
6118 xmlDictReference(ret->comp->dict);
6119 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006120
6121 return(ret);
6122}
6123
6124/**
6125 * xmlXPathCompParserContext:
6126 * @comp: the XPath compiled expression
6127 * @ctxt: the XPath context
6128 *
6129 * Create a new xmlXPathParserContext when processing a compiled expression
6130 *
6131 * Returns the xmlXPathParserContext just allocated.
6132 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006133static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006134xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6135 xmlXPathParserContextPtr ret;
6136
6137 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6138 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006139 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006140 return(NULL);
6141 }
6142 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6143
Owen Taylor3473f882001-02-23 17:55:21 +00006144 /* Allocate the value stack */
Daniel Veillard45490ae2008-07-29 09:13:19 +00006145 ret->valueTab = (xmlXPathObjectPtr *)
Owen Taylor3473f882001-02-23 17:55:21 +00006146 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006147 if (ret->valueTab == NULL) {
6148 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006149 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006150 return(NULL);
6151 }
Owen Taylor3473f882001-02-23 17:55:21 +00006152 ret->valueNr = 0;
6153 ret->valueMax = 10;
6154 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006155
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006156 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006157 ret->comp = comp;
6158
Owen Taylor3473f882001-02-23 17:55:21 +00006159 return(ret);
6160}
6161
6162/**
6163 * xmlXPathFreeParserContext:
6164 * @ctxt: the context to free
6165 *
6166 * Free up an xmlXPathParserContext
6167 */
6168void
6169xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6170 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006171 xmlFree(ctxt->valueTab);
6172 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00006173 if (ctxt->comp != NULL) {
6174#ifdef XPATH_STREAMING
6175 if (ctxt->comp->stream != NULL) {
6176 xmlFreePatternList(ctxt->comp->stream);
6177 ctxt->comp->stream = NULL;
6178 }
6179#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006180 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard56de87e2005-02-16 00:22:29 +00006181 }
Owen Taylor3473f882001-02-23 17:55:21 +00006182 xmlFree(ctxt);
6183}
6184
6185/************************************************************************
6186 * *
6187 * The implicit core function library *
6188 * *
6189 ************************************************************************/
6190
Owen Taylor3473f882001-02-23 17:55:21 +00006191/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006192 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00006193 * @node: a node pointer
6194 *
6195 * Function computing the beginning of the string value of the node,
6196 * used to speed up comparisons
6197 *
6198 * Returns an int usable as a hash
6199 */
6200static unsigned int
6201xmlXPathNodeValHash(xmlNodePtr node) {
6202 int len = 2;
6203 const xmlChar * string = NULL;
6204 xmlNodePtr tmp = NULL;
6205 unsigned int ret = 0;
6206
6207 if (node == NULL)
6208 return(0);
6209
Daniel Veillard9adc0462003-03-24 18:39:54 +00006210 if (node->type == XML_DOCUMENT_NODE) {
6211 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6212 if (tmp == NULL)
6213 node = node->children;
6214 else
6215 node = tmp;
6216
6217 if (node == NULL)
6218 return(0);
6219 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006220
6221 switch (node->type) {
6222 case XML_COMMENT_NODE:
6223 case XML_PI_NODE:
6224 case XML_CDATA_SECTION_NODE:
6225 case XML_TEXT_NODE:
6226 string = node->content;
6227 if (string == NULL)
6228 return(0);
6229 if (string[0] == 0)
6230 return(0);
6231 return(((unsigned int) string[0]) +
6232 (((unsigned int) string[1]) << 8));
6233 case XML_NAMESPACE_DECL:
6234 string = ((xmlNsPtr)node)->href;
6235 if (string == NULL)
6236 return(0);
6237 if (string[0] == 0)
6238 return(0);
6239 return(((unsigned int) string[0]) +
6240 (((unsigned int) string[1]) << 8));
6241 case XML_ATTRIBUTE_NODE:
6242 tmp = ((xmlAttrPtr) node)->children;
6243 break;
6244 case XML_ELEMENT_NODE:
6245 tmp = node->children;
6246 break;
6247 default:
6248 return(0);
6249 }
6250 while (tmp != NULL) {
6251 switch (tmp->type) {
6252 case XML_COMMENT_NODE:
6253 case XML_PI_NODE:
6254 case XML_CDATA_SECTION_NODE:
6255 case XML_TEXT_NODE:
6256 string = tmp->content;
6257 break;
6258 case XML_NAMESPACE_DECL:
6259 string = ((xmlNsPtr)tmp)->href;
6260 break;
6261 default:
6262 break;
6263 }
6264 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006265 if (len == 1) {
6266 return(ret + (((unsigned int) string[0]) << 8));
6267 }
6268 if (string[1] == 0) {
6269 len = 1;
6270 ret = (unsigned int) string[0];
6271 } else {
6272 return(((unsigned int) string[0]) +
6273 (((unsigned int) string[1]) << 8));
6274 }
6275 }
6276 /*
6277 * Skip to next node
6278 */
6279 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6280 if (tmp->children->type != XML_ENTITY_DECL) {
6281 tmp = tmp->children;
6282 continue;
6283 }
6284 }
6285 if (tmp == node)
6286 break;
6287
6288 if (tmp->next != NULL) {
6289 tmp = tmp->next;
6290 continue;
6291 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00006292
Daniel Veillardf06307e2001-07-03 10:35:50 +00006293 do {
6294 tmp = tmp->parent;
6295 if (tmp == NULL)
6296 break;
6297 if (tmp == node) {
6298 tmp = NULL;
6299 break;
6300 }
6301 if (tmp->next != NULL) {
6302 tmp = tmp->next;
6303 break;
6304 }
6305 } while (tmp != NULL);
6306 }
6307 return(ret);
6308}
6309
6310/**
6311 * xmlXPathStringHash:
6312 * @string: a string
6313 *
6314 * Function computing the beginning of the string value of the node,
6315 * used to speed up comparisons
6316 *
6317 * Returns an int usable as a hash
6318 */
6319static unsigned int
6320xmlXPathStringHash(const xmlChar * string) {
6321 if (string == NULL)
6322 return((unsigned int) 0);
6323 if (string[0] == 0)
6324 return(0);
6325 return(((unsigned int) string[0]) +
6326 (((unsigned int) string[1]) << 8));
6327}
6328
6329/**
Owen Taylor3473f882001-02-23 17:55:21 +00006330 * xmlXPathCompareNodeSetFloat:
6331 * @ctxt: the XPath Parser context
6332 * @inf: less than (1) or greater than (0)
6333 * @strict: is the comparison strict
6334 * @arg: the node set
6335 * @f: the value
6336 *
6337 * Implement the compare operation between a nodeset and a number
6338 * @ns < @val (1, 1, ...
6339 * @ns <= @val (1, 0, ...
6340 * @ns > @val (0, 1, ...
6341 * @ns >= @val (0, 0, ...
6342 *
6343 * If one object to be compared is a node-set and the other is a number,
6344 * then the comparison will be true if and only if there is a node in the
6345 * node-set such that the result of performing the comparison on the number
6346 * to be compared and on the result of converting the string-value of that
6347 * node to a number using the number function is true.
6348 *
6349 * Returns 0 or 1 depending on the results of the test.
6350 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006351static int
Owen Taylor3473f882001-02-23 17:55:21 +00006352xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6353 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6354 int i, ret = 0;
6355 xmlNodeSetPtr ns;
6356 xmlChar *str2;
6357
6358 if ((f == NULL) || (arg == NULL) ||
6359 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006360 xmlXPathReleaseObject(ctxt->context, arg);
6361 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006362 return(0);
6363 }
6364 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006365 if (ns != NULL) {
6366 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006367 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006368 if (str2 != NULL) {
6369 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006370 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006371 xmlFree(str2);
6372 xmlXPathNumberFunction(ctxt, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006373 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006374 ret = xmlXPathCompareValues(ctxt, inf, strict);
6375 if (ret)
6376 break;
6377 }
6378 }
Owen Taylor3473f882001-02-23 17:55:21 +00006379 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006380 xmlXPathReleaseObject(ctxt->context, arg);
6381 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006382 return(ret);
6383}
6384
6385/**
6386 * xmlXPathCompareNodeSetString:
6387 * @ctxt: the XPath Parser context
6388 * @inf: less than (1) or greater than (0)
6389 * @strict: is the comparison strict
6390 * @arg: the node set
6391 * @s: the value
6392 *
6393 * Implement the compare operation between a nodeset and a string
6394 * @ns < @val (1, 1, ...
6395 * @ns <= @val (1, 0, ...
6396 * @ns > @val (0, 1, ...
6397 * @ns >= @val (0, 0, ...
6398 *
6399 * If one object to be compared is a node-set and the other is a string,
6400 * then the comparison will be true if and only if there is a node in
6401 * the node-set such that the result of performing the comparison on the
6402 * string-value of the node and the other string is true.
6403 *
6404 * Returns 0 or 1 depending on the results of the test.
6405 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006406static int
Owen Taylor3473f882001-02-23 17:55:21 +00006407xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6408 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6409 int i, ret = 0;
6410 xmlNodeSetPtr ns;
6411 xmlChar *str2;
6412
6413 if ((s == NULL) || (arg == NULL) ||
6414 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006415 xmlXPathReleaseObject(ctxt->context, arg);
6416 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006417 return(0);
6418 }
6419 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006420 if (ns != NULL) {
6421 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006422 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006423 if (str2 != NULL) {
6424 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006425 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006426 xmlFree(str2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006427 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006428 ret = xmlXPathCompareValues(ctxt, inf, strict);
6429 if (ret)
6430 break;
6431 }
6432 }
Owen Taylor3473f882001-02-23 17:55:21 +00006433 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006434 xmlXPathReleaseObject(ctxt->context, arg);
6435 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006436 return(ret);
6437}
6438
6439/**
6440 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006441 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00006442 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006443 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00006444 * @arg2: the second node set object
6445 *
6446 * Implement the compare operation on nodesets:
6447 *
6448 * If both objects to be compared are node-sets, then the comparison
6449 * will be true if and only if there is a node in the first node-set
6450 * and a node in the second node-set such that the result of performing
Daniel Veillard45490ae2008-07-29 09:13:19 +00006451 * the comparison on the string-values of the two nodes is true.
Owen Taylor3473f882001-02-23 17:55:21 +00006452 * ....
6453 * When neither object to be compared is a node-set and the operator
6454 * is <=, <, >= or >, then the objects are compared by converting both
6455 * objects to numbers and comparing the numbers according to IEEE 754.
6456 * ....
6457 * The number function converts its argument to a number as follows:
6458 * - a string that consists of optional whitespace followed by an
6459 * optional minus sign followed by a Number followed by whitespace
6460 * is converted to the IEEE 754 number that is nearest (according
6461 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6462 * represented by the string; any other string is converted to NaN
6463 *
6464 * Conclusion all nodes need to be converted first to their string value
Daniel Veillard45490ae2008-07-29 09:13:19 +00006465 * and then the comparison must be done when possible
Owen Taylor3473f882001-02-23 17:55:21 +00006466 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006467static int
6468xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00006469 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6470 int i, j, init = 0;
6471 double val1;
6472 double *values2;
6473 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006474 xmlNodeSetPtr ns1;
6475 xmlNodeSetPtr ns2;
6476
6477 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006478 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6479 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006480 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006481 }
Owen Taylor3473f882001-02-23 17:55:21 +00006482 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006483 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6484 xmlXPathFreeObject(arg1);
6485 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006486 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006487 }
Owen Taylor3473f882001-02-23 17:55:21 +00006488
6489 ns1 = arg1->nodesetval;
6490 ns2 = arg2->nodesetval;
6491
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006492 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006493 xmlXPathFreeObject(arg1);
6494 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006495 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006496 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006497 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006498 xmlXPathFreeObject(arg1);
6499 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006500 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006501 }
Owen Taylor3473f882001-02-23 17:55:21 +00006502
6503 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6504 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006505 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00006506 xmlXPathFreeObject(arg1);
6507 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006508 return(0);
6509 }
6510 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006511 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00006512 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00006513 continue;
6514 for (j = 0;j < ns2->nodeNr;j++) {
6515 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006516 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00006517 }
Daniel Veillardcda96922001-08-21 10:56:31 +00006518 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00006519 continue;
Daniel Veillard45490ae2008-07-29 09:13:19 +00006520 if (inf && strict)
Owen Taylor3473f882001-02-23 17:55:21 +00006521 ret = (val1 < values2[j]);
6522 else if (inf && !strict)
6523 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 if (ret)
6529 break;
6530 }
6531 if (ret)
6532 break;
6533 init = 1;
6534 }
6535 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006536 xmlXPathFreeObject(arg1);
6537 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006538 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006539}
6540
6541/**
6542 * xmlXPathCompareNodeSetValue:
6543 * @ctxt: the XPath Parser context
6544 * @inf: less than (1) or greater than (0)
6545 * @strict: is the comparison strict
6546 * @arg: the node set
6547 * @val: the value
6548 *
6549 * Implement the compare operation between a nodeset and a value
6550 * @ns < @val (1, 1, ...
6551 * @ns <= @val (1, 0, ...
6552 * @ns > @val (0, 1, ...
6553 * @ns >= @val (0, 0, ...
6554 *
6555 * If one object to be compared is a node-set and the other is a boolean,
6556 * then the comparison will be true if and only if the result of performing
6557 * the comparison on the boolean and on the result of converting
6558 * the node-set to a boolean using the boolean function is true.
6559 *
6560 * Returns 0 or 1 depending on the results of the test.
6561 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006562static int
Owen Taylor3473f882001-02-23 17:55:21 +00006563xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6564 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6565 if ((val == NULL) || (arg == NULL) ||
6566 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6567 return(0);
6568
6569 switch(val->type) {
6570 case XPATH_NUMBER:
6571 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6572 case XPATH_NODESET:
6573 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006574 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00006575 case XPATH_STRING:
6576 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6577 case XPATH_BOOLEAN:
6578 valuePush(ctxt, arg);
6579 xmlXPathBooleanFunction(ctxt, 1);
6580 valuePush(ctxt, val);
6581 return(xmlXPathCompareValues(ctxt, inf, strict));
6582 default:
6583 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00006584 }
6585 return(0);
6586}
6587
6588/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006589 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00006590 * @arg: the nodeset object argument
6591 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00006592 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006593 *
6594 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6595 * If one object to be compared is a node-set and the other is a string,
6596 * then the comparison will be true if and only if there is a node in
6597 * the node-set such that the result of performing the comparison on the
6598 * string-value of the node and the other string is true.
6599 *
6600 * Returns 0 or 1 depending on the results of the test.
6601 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006602static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006603xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006604{
Owen Taylor3473f882001-02-23 17:55:21 +00006605 int i;
6606 xmlNodeSetPtr ns;
6607 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006608 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00006609
6610 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00006611 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6612 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006613 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00006614 /*
6615 * A NULL nodeset compared with a string is always false
6616 * (since there is no node equal, and no node not equal)
6617 */
6618 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00006619 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00006620 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006621 for (i = 0; i < ns->nodeNr; i++) {
6622 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6623 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6624 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6625 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006626 if (neq)
6627 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006628 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00006629 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6630 if (neq)
6631 continue;
6632 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006633 } else if (neq) {
6634 if (str2 != NULL)
6635 xmlFree(str2);
6636 return (1);
6637 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006638 if (str2 != NULL)
6639 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006640 } else if (neq)
6641 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00006642 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006643 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006644}
6645
6646/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006647 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00006648 * @arg: the nodeset object argument
6649 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00006650 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006651 *
6652 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6653 * If one object to be compared is a node-set and the other is a number,
6654 * then the comparison will be true if and only if there is a node in
6655 * the node-set such that the result of performing the comparison on the
6656 * number to be compared and on the result of converting the string-value
6657 * of that node to a number using the number function is true.
6658 *
6659 * Returns 0 or 1 depending on the results of the test.
6660 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006661static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006662xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6663 xmlXPathObjectPtr arg, double f, int neq) {
6664 int i, ret=0;
6665 xmlNodeSetPtr ns;
6666 xmlChar *str2;
6667 xmlXPathObjectPtr val;
6668 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00006669
6670 if ((arg == NULL) ||
6671 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6672 return(0);
6673
William M. Brack0c022ad2002-07-12 00:56:01 +00006674 ns = arg->nodesetval;
6675 if (ns != NULL) {
6676 for (i=0;i<ns->nodeNr;i++) {
6677 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6678 if (str2 != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006679 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
William M. Brack0c022ad2002-07-12 00:56:01 +00006680 xmlFree(str2);
6681 xmlXPathNumberFunction(ctxt, 1);
6682 val = valuePop(ctxt);
6683 v = val->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006684 xmlXPathReleaseObject(ctxt->context, val);
William M. Brack0c022ad2002-07-12 00:56:01 +00006685 if (!xmlXPathIsNaN(v)) {
6686 if ((!neq) && (v==f)) {
6687 ret = 1;
6688 break;
6689 } else if ((neq) && (v!=f)) {
6690 ret = 1;
6691 break;
6692 }
William M. Brack32f0f712005-07-14 07:00:33 +00006693 } else { /* NaN is unequal to any value */
6694 if (neq)
6695 ret = 1;
William M. Brack0c022ad2002-07-12 00:56:01 +00006696 }
6697 }
6698 }
6699 }
6700
6701 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006702}
6703
6704
6705/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006706 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00006707 * @arg1: first nodeset object argument
6708 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00006709 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006710 *
William M. Brack0c022ad2002-07-12 00:56:01 +00006711 * Implement the equal / not equal operation on XPath nodesets:
6712 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00006713 * If both objects to be compared are node-sets, then the comparison
6714 * will be true if and only if there is a node in the first node-set and
6715 * a node in the second node-set such that the result of performing the
6716 * comparison on the string-values of the two nodes is true.
6717 *
6718 * (needless to say, this is a costly operation)
6719 *
6720 * Returns 0 or 1 depending on the results of the test.
6721 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006722static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006723xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00006724 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006725 unsigned int *hashs1;
6726 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00006727 xmlChar **values1;
6728 xmlChar **values2;
6729 int ret = 0;
6730 xmlNodeSetPtr ns1;
6731 xmlNodeSetPtr ns2;
6732
6733 if ((arg1 == NULL) ||
6734 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6735 return(0);
6736 if ((arg2 == NULL) ||
6737 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6738 return(0);
6739
6740 ns1 = arg1->nodesetval;
6741 ns2 = arg2->nodesetval;
6742
Daniel Veillard911f49a2001-04-07 15:39:35 +00006743 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006744 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006745 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006746 return(0);
6747
6748 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00006749 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00006750 */
William M. Brack0c022ad2002-07-12 00:56:01 +00006751 if (neq == 0)
6752 for (i = 0;i < ns1->nodeNr;i++)
6753 for (j = 0;j < ns2->nodeNr;j++)
6754 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6755 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006756
6757 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006758 if (values1 == NULL) {
6759 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006760 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006761 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006762 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6763 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006764 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006765 xmlFree(values1);
6766 return(0);
6767 }
Owen Taylor3473f882001-02-23 17:55:21 +00006768 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6769 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6770 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006771 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006772 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00006773 xmlFree(values1);
6774 return(0);
6775 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006776 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6777 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006778 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006779 xmlFree(hashs1);
6780 xmlFree(values1);
6781 xmlFree(values2);
6782 return(0);
6783 }
Owen Taylor3473f882001-02-23 17:55:21 +00006784 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6785 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006786 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006787 for (j = 0;j < ns2->nodeNr;j++) {
6788 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006789 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006790 if (hashs1[i] != hashs2[j]) {
6791 if (neq) {
6792 ret = 1;
6793 break;
6794 }
6795 }
6796 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006797 if (values1[i] == NULL)
6798 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6799 if (values2[j] == NULL)
6800 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006801 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006802 if (ret)
6803 break;
6804 }
Owen Taylor3473f882001-02-23 17:55:21 +00006805 }
6806 if (ret)
6807 break;
6808 }
6809 for (i = 0;i < ns1->nodeNr;i++)
6810 if (values1[i] != NULL)
6811 xmlFree(values1[i]);
6812 for (j = 0;j < ns2->nodeNr;j++)
6813 if (values2[j] != NULL)
6814 xmlFree(values2[j]);
6815 xmlFree(values1);
6816 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006817 xmlFree(hashs1);
6818 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00006819 return(ret);
6820}
6821
William M. Brack0c022ad2002-07-12 00:56:01 +00006822static int
6823xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6824 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00006825 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00006826 /*
6827 *At this point we are assured neither arg1 nor arg2
6828 *is a nodeset, so we can just pick the appropriate routine.
6829 */
Owen Taylor3473f882001-02-23 17:55:21 +00006830 switch (arg1->type) {
6831 case XPATH_UNDEFINED:
6832#ifdef DEBUG_EXPR
6833 xmlGenericError(xmlGenericErrorContext,
6834 "Equal: undefined\n");
6835#endif
6836 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006837 case XPATH_BOOLEAN:
6838 switch (arg2->type) {
6839 case XPATH_UNDEFINED:
6840#ifdef DEBUG_EXPR
6841 xmlGenericError(xmlGenericErrorContext,
6842 "Equal: undefined\n");
6843#endif
6844 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006845 case XPATH_BOOLEAN:
6846#ifdef DEBUG_EXPR
6847 xmlGenericError(xmlGenericErrorContext,
6848 "Equal: %d boolean %d \n",
6849 arg1->boolval, arg2->boolval);
6850#endif
6851 ret = (arg1->boolval == arg2->boolval);
6852 break;
6853 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00006854 ret = (arg1->boolval ==
6855 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006856 break;
6857 case XPATH_STRING:
6858 if ((arg2->stringval == NULL) ||
6859 (arg2->stringval[0] == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00006860 else
Owen Taylor3473f882001-02-23 17:55:21 +00006861 ret = 1;
6862 ret = (arg1->boolval == ret);
6863 break;
6864 case XPATH_USERS:
6865 case XPATH_POINT:
6866 case XPATH_RANGE:
6867 case XPATH_LOCATIONSET:
6868 TODO
6869 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006870 case XPATH_NODESET:
6871 case XPATH_XSLT_TREE:
6872 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006873 }
6874 break;
6875 case XPATH_NUMBER:
6876 switch (arg2->type) {
6877 case XPATH_UNDEFINED:
6878#ifdef DEBUG_EXPR
6879 xmlGenericError(xmlGenericErrorContext,
6880 "Equal: undefined\n");
6881#endif
6882 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006883 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00006884 ret = (arg2->boolval==
6885 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006886 break;
6887 case XPATH_STRING:
6888 valuePush(ctxt, arg2);
6889 xmlXPathNumberFunction(ctxt, 1);
6890 arg2 = valuePop(ctxt);
6891 /* no break on purpose */
6892 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006893 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00006894 if (xmlXPathIsNaN(arg1->floatval) ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00006895 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00006896 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006897 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6898 if (xmlXPathIsInf(arg2->floatval) == 1)
6899 ret = 1;
6900 else
6901 ret = 0;
6902 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6903 if (xmlXPathIsInf(arg2->floatval) == -1)
6904 ret = 1;
6905 else
6906 ret = 0;
6907 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6908 if (xmlXPathIsInf(arg1->floatval) == 1)
6909 ret = 1;
6910 else
6911 ret = 0;
6912 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6913 if (xmlXPathIsInf(arg1->floatval) == -1)
6914 ret = 1;
6915 else
6916 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00006917 } else {
6918 ret = (arg1->floatval == arg2->floatval);
6919 }
Owen Taylor3473f882001-02-23 17:55:21 +00006920 break;
6921 case XPATH_USERS:
6922 case XPATH_POINT:
6923 case XPATH_RANGE:
6924 case XPATH_LOCATIONSET:
6925 TODO
6926 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006927 case XPATH_NODESET:
6928 case XPATH_XSLT_TREE:
6929 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006930 }
6931 break;
6932 case XPATH_STRING:
6933 switch (arg2->type) {
6934 case XPATH_UNDEFINED:
6935#ifdef DEBUG_EXPR
6936 xmlGenericError(xmlGenericErrorContext,
6937 "Equal: undefined\n");
6938#endif
6939 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006940 case XPATH_BOOLEAN:
6941 if ((arg1->stringval == NULL) ||
6942 (arg1->stringval[0] == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00006943 else
Owen Taylor3473f882001-02-23 17:55:21 +00006944 ret = 1;
6945 ret = (arg2->boolval == ret);
6946 break;
6947 case XPATH_STRING:
6948 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6949 break;
6950 case XPATH_NUMBER:
6951 valuePush(ctxt, arg1);
6952 xmlXPathNumberFunction(ctxt, 1);
6953 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006954 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00006955 if (xmlXPathIsNaN(arg1->floatval) ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00006956 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00006957 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006958 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6959 if (xmlXPathIsInf(arg2->floatval) == 1)
6960 ret = 1;
6961 else
6962 ret = 0;
6963 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6964 if (xmlXPathIsInf(arg2->floatval) == -1)
6965 ret = 1;
6966 else
6967 ret = 0;
6968 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6969 if (xmlXPathIsInf(arg1->floatval) == 1)
6970 ret = 1;
6971 else
6972 ret = 0;
6973 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6974 if (xmlXPathIsInf(arg1->floatval) == -1)
6975 ret = 1;
6976 else
6977 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00006978 } else {
6979 ret = (arg1->floatval == arg2->floatval);
6980 }
Owen Taylor3473f882001-02-23 17:55:21 +00006981 break;
6982 case XPATH_USERS:
6983 case XPATH_POINT:
6984 case XPATH_RANGE:
6985 case XPATH_LOCATIONSET:
6986 TODO
6987 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006988 case XPATH_NODESET:
6989 case XPATH_XSLT_TREE:
6990 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006991 }
6992 break;
6993 case XPATH_USERS:
6994 case XPATH_POINT:
6995 case XPATH_RANGE:
6996 case XPATH_LOCATIONSET:
6997 TODO
6998 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006999 case XPATH_NODESET:
7000 case XPATH_XSLT_TREE:
7001 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007002 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007003 xmlXPathReleaseObject(ctxt->context, arg1);
7004 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007005 return(ret);
7006}
7007
William M. Brack0c022ad2002-07-12 00:56:01 +00007008/**
7009 * xmlXPathEqualValues:
7010 * @ctxt: the XPath Parser context
7011 *
7012 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7013 *
7014 * Returns 0 or 1 depending on the results of the test.
7015 */
7016int
7017xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7018 xmlXPathObjectPtr arg1, arg2, argtmp;
7019 int ret = 0;
7020
Daniel Veillard6128c012004-11-08 17:16:15 +00007021 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007022 arg2 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007023 arg1 = valuePop(ctxt);
7024 if ((arg1 == NULL) || (arg2 == NULL)) {
7025 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007026 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007027 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007028 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007029 XP_ERROR0(XPATH_INVALID_OPERAND);
7030 }
7031
7032 if (arg1 == arg2) {
7033#ifdef DEBUG_EXPR
7034 xmlGenericError(xmlGenericErrorContext,
7035 "Equal: by pointer\n");
7036#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00007037 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007038 return(1);
7039 }
7040
7041 /*
7042 *If either argument is a nodeset, it's a 'special case'
7043 */
7044 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7045 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7046 /*
7047 *Hack it to assure arg1 is the nodeset
7048 */
7049 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7050 argtmp = arg2;
7051 arg2 = arg1;
7052 arg1 = argtmp;
7053 }
7054 switch (arg2->type) {
7055 case XPATH_UNDEFINED:
7056#ifdef DEBUG_EXPR
7057 xmlGenericError(xmlGenericErrorContext,
7058 "Equal: undefined\n");
7059#endif
7060 break;
7061 case XPATH_NODESET:
7062 case XPATH_XSLT_TREE:
7063 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7064 break;
7065 case XPATH_BOOLEAN:
7066 if ((arg1->nodesetval == NULL) ||
7067 (arg1->nodesetval->nodeNr == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007068 else
William M. Brack0c022ad2002-07-12 00:56:01 +00007069 ret = 1;
7070 ret = (ret == arg2->boolval);
7071 break;
7072 case XPATH_NUMBER:
7073 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7074 break;
7075 case XPATH_STRING:
7076 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7077 break;
7078 case XPATH_USERS:
7079 case XPATH_POINT:
7080 case XPATH_RANGE:
7081 case XPATH_LOCATIONSET:
7082 TODO
7083 break;
7084 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007085 xmlXPathReleaseObject(ctxt->context, arg1);
7086 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007087 return(ret);
7088 }
7089
7090 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7091}
7092
7093/**
7094 * xmlXPathNotEqualValues:
7095 * @ctxt: the XPath Parser context
7096 *
7097 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7098 *
7099 * Returns 0 or 1 depending on the results of the test.
7100 */
7101int
7102xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7103 xmlXPathObjectPtr arg1, arg2, argtmp;
7104 int ret = 0;
7105
Daniel Veillard6128c012004-11-08 17:16:15 +00007106 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007107 arg2 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007108 arg1 = valuePop(ctxt);
7109 if ((arg1 == NULL) || (arg2 == NULL)) {
7110 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007111 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007112 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007113 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007114 XP_ERROR0(XPATH_INVALID_OPERAND);
7115 }
7116
7117 if (arg1 == arg2) {
7118#ifdef DEBUG_EXPR
7119 xmlGenericError(xmlGenericErrorContext,
7120 "NotEqual: by pointer\n");
7121#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007122 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007123 return(0);
7124 }
7125
7126 /*
7127 *If either argument is a nodeset, it's a 'special case'
7128 */
7129 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7130 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7131 /*
7132 *Hack it to assure arg1 is the nodeset
7133 */
7134 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7135 argtmp = arg2;
7136 arg2 = arg1;
7137 arg1 = argtmp;
7138 }
7139 switch (arg2->type) {
7140 case XPATH_UNDEFINED:
7141#ifdef DEBUG_EXPR
7142 xmlGenericError(xmlGenericErrorContext,
7143 "NotEqual: undefined\n");
7144#endif
7145 break;
7146 case XPATH_NODESET:
7147 case XPATH_XSLT_TREE:
7148 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7149 break;
7150 case XPATH_BOOLEAN:
7151 if ((arg1->nodesetval == NULL) ||
7152 (arg1->nodesetval->nodeNr == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007153 else
William M. Brack0c022ad2002-07-12 00:56:01 +00007154 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00007155 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00007156 break;
7157 case XPATH_NUMBER:
7158 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7159 break;
7160 case XPATH_STRING:
7161 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7162 break;
7163 case XPATH_USERS:
7164 case XPATH_POINT:
7165 case XPATH_RANGE:
7166 case XPATH_LOCATIONSET:
7167 TODO
7168 break;
7169 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007170 xmlXPathReleaseObject(ctxt->context, arg1);
7171 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007172 return(ret);
7173 }
7174
7175 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7176}
Owen Taylor3473f882001-02-23 17:55:21 +00007177
7178/**
7179 * xmlXPathCompareValues:
7180 * @ctxt: the XPath Parser context
7181 * @inf: less than (1) or greater than (0)
7182 * @strict: is the comparison strict
7183 *
Daniel Veillard45490ae2008-07-29 09:13:19 +00007184 * Implement the compare operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007185 * @arg1 < @arg2 (1, 1, ...
7186 * @arg1 <= @arg2 (1, 0, ...
7187 * @arg1 > @arg2 (0, 1, ...
7188 * @arg1 >= @arg2 (0, 0, ...
7189 *
7190 * When neither object to be compared is a node-set and the operator is
7191 * <=, <, >=, >, then the objects are compared by converted both objects
7192 * to numbers and comparing the numbers according to IEEE 754. The <
7193 * comparison will be true if and only if the first number is less than the
7194 * second number. The <= comparison will be true if and only if the first
7195 * number is less than or equal to the second number. The > comparison
7196 * will be true if and only if the first number is greater than the second
7197 * number. The >= comparison will be true if and only if the first number
7198 * is greater than or equal to the second number.
7199 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007200 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00007201 */
7202int
7203xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007204 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007205 xmlXPathObjectPtr arg1, arg2;
7206
Daniel Veillard6128c012004-11-08 17:16:15 +00007207 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007208 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007209 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007210 if ((arg1 == NULL) || (arg2 == NULL)) {
7211 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007212 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007213 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007214 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007215 XP_ERROR0(XPATH_INVALID_OPERAND);
7216 }
7217
William M. Brack0c022ad2002-07-12 00:56:01 +00007218 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7219 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
William M. Brackd6e347e2005-04-15 01:34:41 +00007220 /*
7221 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7222 * are not freed from within this routine; they will be freed from the
7223 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7224 */
William M. Brack0c022ad2002-07-12 00:56:01 +00007225 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7226 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007227 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007228 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00007229 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007230 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7231 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007232 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007233 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7234 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00007235 }
7236 }
7237 return(ret);
7238 }
7239
7240 if (arg1->type != XPATH_NUMBER) {
7241 valuePush(ctxt, arg1);
7242 xmlXPathNumberFunction(ctxt, 1);
7243 arg1 = valuePop(ctxt);
7244 }
7245 if (arg1->type != XPATH_NUMBER) {
7246 xmlXPathFreeObject(arg1);
7247 xmlXPathFreeObject(arg2);
7248 XP_ERROR0(XPATH_INVALID_OPERAND);
7249 }
7250 if (arg2->type != XPATH_NUMBER) {
7251 valuePush(ctxt, arg2);
7252 xmlXPathNumberFunction(ctxt, 1);
7253 arg2 = valuePop(ctxt);
7254 }
7255 if (arg2->type != XPATH_NUMBER) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007256 xmlXPathReleaseObject(ctxt->context, arg1);
7257 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007258 XP_ERROR0(XPATH_INVALID_OPERAND);
7259 }
7260 /*
7261 * Add tests for infinity and nan
7262 * => feedback on 3.4 for Inf and NaN
7263 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007264 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00007265 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007266 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007267 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007268 arg1i=xmlXPathIsInf(arg1->floatval);
7269 arg2i=xmlXPathIsInf(arg2->floatval);
7270 if (inf && strict) {
7271 if ((arg1i == -1 && arg2i != -1) ||
7272 (arg2i == 1 && arg1i != 1)) {
7273 ret = 1;
7274 } else if (arg1i == 0 && arg2i == 0) {
7275 ret = (arg1->floatval < arg2->floatval);
7276 } else {
7277 ret = 0;
7278 }
7279 }
7280 else if (inf && !strict) {
7281 if (arg1i == -1 || arg2i == 1) {
7282 ret = 1;
7283 } else if (arg1i == 0 && arg2i == 0) {
7284 ret = (arg1->floatval <= arg2->floatval);
7285 } else {
7286 ret = 0;
7287 }
7288 }
7289 else if (!inf && strict) {
7290 if ((arg1i == 1 && arg2i != 1) ||
7291 (arg2i == -1 && arg1i != -1)) {
7292 ret = 1;
7293 } else if (arg1i == 0 && arg2i == 0) {
7294 ret = (arg1->floatval > arg2->floatval);
7295 } else {
7296 ret = 0;
7297 }
7298 }
7299 else if (!inf && !strict) {
7300 if (arg1i == 1 || arg2i == -1) {
7301 ret = 1;
7302 } else if (arg1i == 0 && arg2i == 0) {
7303 ret = (arg1->floatval >= arg2->floatval);
7304 } else {
7305 ret = 0;
7306 }
7307 }
Daniel Veillard21458c82002-03-27 16:12:22 +00007308 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007309 xmlXPathReleaseObject(ctxt->context, arg1);
7310 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007311 return(ret);
7312}
7313
7314/**
7315 * xmlXPathValueFlipSign:
7316 * @ctxt: the XPath Parser context
7317 *
7318 * Implement the unary - operation on an XPath object
7319 * The numeric operators convert their operands to numbers as if
7320 * by calling the number function.
7321 */
7322void
7323xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007324 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007325 CAST_TO_NUMBER;
7326 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007327 if (xmlXPathIsNaN(ctxt->value->floatval))
7328 ctxt->value->floatval=xmlXPathNAN;
7329 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7330 ctxt->value->floatval=xmlXPathNINF;
7331 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7332 ctxt->value->floatval=xmlXPathPINF;
7333 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007334 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7335 ctxt->value->floatval = xmlXPathNZERO;
7336 else
7337 ctxt->value->floatval = 0;
7338 }
7339 else
7340 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00007341}
7342
7343/**
7344 * xmlXPathAddValues:
7345 * @ctxt: the XPath Parser context
7346 *
7347 * Implement the add operation on XPath objects:
7348 * The numeric operators convert their operands to numbers as if
7349 * by calling the number function.
7350 */
7351void
7352xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7353 xmlXPathObjectPtr arg;
7354 double val;
7355
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007356 arg = valuePop(ctxt);
7357 if (arg == NULL)
7358 XP_ERROR(XPATH_INVALID_OPERAND);
7359 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007360 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007361 CAST_TO_NUMBER;
7362 CHECK_TYPE(XPATH_NUMBER);
7363 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00007364}
7365
7366/**
7367 * xmlXPathSubValues:
7368 * @ctxt: the XPath Parser context
7369 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007370 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007371 * The numeric operators convert their operands to numbers as if
7372 * by calling the number function.
7373 */
7374void
7375xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7376 xmlXPathObjectPtr arg;
7377 double val;
7378
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007379 arg = valuePop(ctxt);
7380 if (arg == NULL)
7381 XP_ERROR(XPATH_INVALID_OPERAND);
7382 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007383 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007384 CAST_TO_NUMBER;
7385 CHECK_TYPE(XPATH_NUMBER);
7386 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007387}
7388
7389/**
7390 * xmlXPathMultValues:
7391 * @ctxt: the XPath Parser context
7392 *
7393 * Implement the multiply operation on XPath objects:
7394 * The numeric operators convert their operands to numbers as if
7395 * by calling the number function.
7396 */
7397void
7398xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7399 xmlXPathObjectPtr arg;
7400 double val;
7401
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007402 arg = valuePop(ctxt);
7403 if (arg == NULL)
7404 XP_ERROR(XPATH_INVALID_OPERAND);
7405 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007406 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007407 CAST_TO_NUMBER;
7408 CHECK_TYPE(XPATH_NUMBER);
7409 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007410}
7411
7412/**
7413 * xmlXPathDivValues:
7414 * @ctxt: the XPath Parser context
7415 *
7416 * Implement the div operation on XPath objects @arg1 / @arg2:
7417 * The numeric operators convert their operands to numbers as if
7418 * by calling the number function.
7419 */
7420void
7421xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7422 xmlXPathObjectPtr arg;
7423 double val;
7424
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007425 arg = valuePop(ctxt);
7426 if (arg == NULL)
7427 XP_ERROR(XPATH_INVALID_OPERAND);
7428 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007429 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007430 CAST_TO_NUMBER;
7431 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007432 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7433 ctxt->value->floatval = xmlXPathNAN;
7434 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007435 if (ctxt->value->floatval == 0)
7436 ctxt->value->floatval = xmlXPathNAN;
7437 else if (ctxt->value->floatval > 0)
7438 ctxt->value->floatval = xmlXPathNINF;
7439 else if (ctxt->value->floatval < 0)
7440 ctxt->value->floatval = xmlXPathPINF;
7441 }
7442 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007443 if (ctxt->value->floatval == 0)
7444 ctxt->value->floatval = xmlXPathNAN;
7445 else if (ctxt->value->floatval > 0)
7446 ctxt->value->floatval = xmlXPathPINF;
7447 else if (ctxt->value->floatval < 0)
7448 ctxt->value->floatval = xmlXPathNINF;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007449 } else
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007450 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007451}
7452
7453/**
7454 * xmlXPathModValues:
7455 * @ctxt: the XPath Parser context
7456 *
7457 * Implement the mod operation on XPath objects: @arg1 / @arg2
7458 * The numeric operators convert their operands to numbers as if
7459 * by calling the number function.
7460 */
7461void
7462xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7463 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00007464 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00007465
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007466 arg = valuePop(ctxt);
7467 if (arg == NULL)
7468 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007469 arg2 = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007470 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007471 CAST_TO_NUMBER;
7472 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007473 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00007474 if (arg2 == 0)
7475 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007476 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00007477 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007478 }
Owen Taylor3473f882001-02-23 17:55:21 +00007479}
7480
7481/************************************************************************
7482 * *
7483 * The traversal functions *
7484 * *
7485 ************************************************************************/
7486
Owen Taylor3473f882001-02-23 17:55:21 +00007487/*
7488 * A traversal function enumerates nodes along an axis.
7489 * Initially it must be called with NULL, and it indicates
7490 * termination on the axis by returning NULL.
7491 */
7492typedef xmlNodePtr (*xmlXPathTraversalFunction)
7493 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7494
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007495/*
7496 * xmlXPathTraversalFunctionExt:
7497 * A traversal function enumerates nodes along an axis.
7498 * Initially it must be called with NULL, and it indicates
7499 * termination on the axis by returning NULL.
7500 * The context node of the traversal is specified via @contextNode.
7501 */
7502typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7503 (xmlNodePtr cur, xmlNodePtr contextNode);
7504
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00007505/*
7506 * xmlXPathNodeSetMergeFunction:
7507 * Used for merging node sets in xmlXPathCollectAndTest().
7508 */
7509typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7510 (xmlNodeSetPtr, xmlNodeSetPtr, int);
7511
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007512
Owen Taylor3473f882001-02-23 17:55:21 +00007513/**
7514 * xmlXPathNextSelf:
7515 * @ctxt: the XPath Parser context
7516 * @cur: the current node in the traversal
7517 *
7518 * Traversal function for the "self" direction
7519 * The self axis contains just the context node itself
7520 *
7521 * Returns the next element following that axis
7522 */
7523xmlNodePtr
7524xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007525 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007526 if (cur == NULL)
7527 return(ctxt->context->node);
7528 return(NULL);
7529}
7530
7531/**
7532 * xmlXPathNextChild:
7533 * @ctxt: the XPath Parser context
7534 * @cur: the current node in the traversal
7535 *
7536 * Traversal function for the "child" direction
7537 * The child axis contains the children of the context node in document order.
7538 *
7539 * Returns the next element following that axis
7540 */
7541xmlNodePtr
7542xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007543 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007544 if (cur == NULL) {
7545 if (ctxt->context->node == NULL) return(NULL);
7546 switch (ctxt->context->node->type) {
7547 case XML_ELEMENT_NODE:
7548 case XML_TEXT_NODE:
7549 case XML_CDATA_SECTION_NODE:
7550 case XML_ENTITY_REF_NODE:
7551 case XML_ENTITY_NODE:
7552 case XML_PI_NODE:
7553 case XML_COMMENT_NODE:
7554 case XML_NOTATION_NODE:
7555 case XML_DTD_NODE:
7556 return(ctxt->context->node->children);
7557 case XML_DOCUMENT_NODE:
7558 case XML_DOCUMENT_TYPE_NODE:
7559 case XML_DOCUMENT_FRAG_NODE:
7560 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007561#ifdef LIBXML_DOCB_ENABLED
7562 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007563#endif
7564 return(((xmlDocPtr) ctxt->context->node)->children);
7565 case XML_ELEMENT_DECL:
7566 case XML_ATTRIBUTE_DECL:
7567 case XML_ENTITY_DECL:
7568 case XML_ATTRIBUTE_NODE:
7569 case XML_NAMESPACE_DECL:
7570 case XML_XINCLUDE_START:
7571 case XML_XINCLUDE_END:
7572 return(NULL);
7573 }
7574 return(NULL);
7575 }
7576 if ((cur->type == XML_DOCUMENT_NODE) ||
7577 (cur->type == XML_HTML_DOCUMENT_NODE))
7578 return(NULL);
7579 return(cur->next);
7580}
7581
7582/**
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00007583 * xmlXPathNextChildElement:
7584 * @ctxt: the XPath Parser context
7585 * @cur: the current node in the traversal
7586 *
7587 * Traversal function for the "child" direction and nodes of type element.
7588 * The child axis contains the children of the context node in document order.
7589 *
7590 * Returns the next element following that axis
7591 */
7592static xmlNodePtr
7593xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7594 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7595 if (cur == NULL) {
7596 cur = ctxt->context->node;
7597 if (cur == NULL) return(NULL);
7598 /*
7599 * Get the first element child.
7600 */
7601 switch (cur->type) {
7602 case XML_ELEMENT_NODE:
7603 case XML_DOCUMENT_FRAG_NODE:
7604 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7605 case XML_ENTITY_NODE:
7606 cur = cur->children;
7607 if (cur != NULL) {
7608 if (cur->type == XML_ELEMENT_NODE)
7609 return(cur);
7610 do {
7611 cur = cur->next;
7612 } while ((cur != NULL) &&
7613 (cur->type != XML_ELEMENT_NODE));
7614 return(cur);
7615 }
7616 return(NULL);
7617 case XML_DOCUMENT_NODE:
7618 case XML_HTML_DOCUMENT_NODE:
7619#ifdef LIBXML_DOCB_ENABLED
7620 case XML_DOCB_DOCUMENT_NODE:
7621#endif
7622 return(xmlDocGetRootElement((xmlDocPtr) cur));
7623 default:
7624 return(NULL);
7625 }
7626 return(NULL);
7627 }
7628 /*
7629 * Get the next sibling element node.
7630 */
7631 switch (cur->type) {
7632 case XML_ELEMENT_NODE:
7633 case XML_TEXT_NODE:
7634 case XML_ENTITY_REF_NODE:
7635 case XML_ENTITY_NODE:
7636 case XML_CDATA_SECTION_NODE:
7637 case XML_PI_NODE:
7638 case XML_COMMENT_NODE:
7639 case XML_XINCLUDE_END:
7640 break;
7641 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7642 default:
7643 return(NULL);
7644 }
7645 if (cur->next != NULL) {
7646 if (cur->next->type == XML_ELEMENT_NODE)
7647 return(cur->next);
7648 cur = cur->next;
7649 do {
7650 cur = cur->next;
7651 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7652 return(cur);
7653 }
7654 return(NULL);
7655}
7656
7657/**
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007658 * xmlXPathNextDescendantOrSelfElemParent:
7659 * @ctxt: the XPath Parser context
7660 * @cur: the current node in the traversal
7661 *
7662 * Traversal function for the "descendant-or-self" axis.
7663 * Additionally it returns only nodes which can be parents of
7664 * element nodes.
7665 *
7666 *
7667 * Returns the next element following that axis
7668 */
7669static xmlNodePtr
7670xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7671 xmlNodePtr contextNode)
7672{
7673 if (cur == NULL) {
7674 if (contextNode == NULL)
7675 return(NULL);
7676 switch (contextNode->type) {
7677 case XML_ELEMENT_NODE:
7678 case XML_XINCLUDE_START:
7679 case XML_DOCUMENT_FRAG_NODE:
7680 case XML_DOCUMENT_NODE:
7681#ifdef LIBXML_DOCB_ENABLED
7682 case XML_DOCB_DOCUMENT_NODE:
7683#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00007684 case XML_HTML_DOCUMENT_NODE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007685 return(contextNode);
7686 default:
Daniel Veillard45490ae2008-07-29 09:13:19 +00007687 return(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007688 }
7689 return(NULL);
7690 } else {
7691 xmlNodePtr start = cur;
7692
7693 while (cur != NULL) {
7694 switch (cur->type) {
7695 case XML_ELEMENT_NODE:
7696 /* TODO: OK to have XInclude here? */
7697 case XML_XINCLUDE_START:
Daniel Veillard45490ae2008-07-29 09:13:19 +00007698 case XML_DOCUMENT_FRAG_NODE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007699 if (cur != start)
7700 return(cur);
7701 if (cur->children != NULL) {
7702 cur = cur->children;
7703 continue;
7704 }
7705 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007706 /* Not sure if we need those here. */
7707 case XML_DOCUMENT_NODE:
Daniel Veillard17970a72006-10-26 08:55:47 +00007708#ifdef LIBXML_DOCB_ENABLED
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007709 case XML_DOCB_DOCUMENT_NODE:
7710#endif
7711 case XML_HTML_DOCUMENT_NODE:
7712 if (cur != start)
7713 return(cur);
7714 return(xmlDocGetRootElement((xmlDocPtr) cur));
7715 default:
7716 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007717 }
7718
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007719next_sibling:
7720 if ((cur == NULL) || (cur == contextNode))
Daniel Veillard45490ae2008-07-29 09:13:19 +00007721 return(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007722 if (cur->next != NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00007723 cur = cur->next;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007724 } else {
7725 cur = cur->parent;
7726 goto next_sibling;
7727 }
7728 }
7729 }
7730 return(NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007731}
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007732
7733/**
Owen Taylor3473f882001-02-23 17:55:21 +00007734 * xmlXPathNextDescendant:
7735 * @ctxt: the XPath Parser context
7736 * @cur: the current node in the traversal
7737 *
7738 * Traversal function for the "descendant" direction
7739 * the descendant axis contains the descendants of the context node in document
7740 * order; a descendant is a child or a child of a child and so on.
7741 *
7742 * Returns the next element following that axis
7743 */
7744xmlNodePtr
7745xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007746 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007747 if (cur == NULL) {
7748 if (ctxt->context->node == NULL)
7749 return(NULL);
7750 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7751 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7752 return(NULL);
7753
7754 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7755 return(ctxt->context->doc->children);
7756 return(ctxt->context->node->children);
7757 }
7758
Daniel Veillard567e1b42001-08-01 15:53:47 +00007759 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007760 /*
7761 * Do not descend on entities declarations
7762 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00007763 if (cur->children->type != XML_ENTITY_DECL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007764 cur = cur->children;
7765 /*
7766 * Skip DTDs
7767 */
7768 if (cur->type != XML_DTD_NODE)
7769 return(cur);
7770 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00007771 }
7772
7773 if (cur == ctxt->context->node) return(NULL);
7774
Daniel Veillard68e9e742002-11-16 15:35:11 +00007775 while (cur->next != NULL) {
7776 cur = cur->next;
7777 if ((cur->type != XML_ENTITY_DECL) &&
7778 (cur->type != XML_DTD_NODE))
7779 return(cur);
7780 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00007781
Owen Taylor3473f882001-02-23 17:55:21 +00007782 do {
7783 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00007784 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00007785 if (cur == ctxt->context->node) return(NULL);
7786 if (cur->next != NULL) {
7787 cur = cur->next;
7788 return(cur);
7789 }
7790 } while (cur != NULL);
7791 return(cur);
7792}
7793
7794/**
7795 * xmlXPathNextDescendantOrSelf:
7796 * @ctxt: the XPath Parser context
7797 * @cur: the current node in the traversal
7798 *
7799 * Traversal function for the "descendant-or-self" direction
7800 * the descendant-or-self axis contains the context node and the descendants
7801 * of the context node in document order; thus the context node is the first
7802 * node on the axis, and the first child of the context node is the second node
7803 * on the axis
7804 *
7805 * Returns the next element following that axis
7806 */
7807xmlNodePtr
7808xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007809 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007810 if (cur == NULL) {
7811 if (ctxt->context->node == NULL)
7812 return(NULL);
7813 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7814 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7815 return(NULL);
7816 return(ctxt->context->node);
7817 }
7818
7819 return(xmlXPathNextDescendant(ctxt, cur));
7820}
7821
7822/**
7823 * xmlXPathNextParent:
7824 * @ctxt: the XPath Parser context
7825 * @cur: the current node in the traversal
7826 *
7827 * Traversal function for the "parent" direction
7828 * The parent axis contains the parent of the context node, if there is one.
7829 *
7830 * Returns the next element following that axis
7831 */
7832xmlNodePtr
7833xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007834 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007835 /*
7836 * the parent of an attribute or namespace node is the element
7837 * to which the attribute or namespace node is attached
7838 * Namespace handling !!!
7839 */
7840 if (cur == NULL) {
7841 if (ctxt->context->node == NULL) return(NULL);
7842 switch (ctxt->context->node->type) {
7843 case XML_ELEMENT_NODE:
7844 case XML_TEXT_NODE:
7845 case XML_CDATA_SECTION_NODE:
7846 case XML_ENTITY_REF_NODE:
7847 case XML_ENTITY_NODE:
7848 case XML_PI_NODE:
7849 case XML_COMMENT_NODE:
7850 case XML_NOTATION_NODE:
7851 case XML_DTD_NODE:
7852 case XML_ELEMENT_DECL:
7853 case XML_ATTRIBUTE_DECL:
7854 case XML_XINCLUDE_START:
7855 case XML_XINCLUDE_END:
7856 case XML_ENTITY_DECL:
7857 if (ctxt->context->node->parent == NULL)
7858 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007859 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007860 ((ctxt->context->node->parent->name[0] == ' ') ||
7861 (xmlStrEqual(ctxt->context->node->parent->name,
7862 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007863 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007864 return(ctxt->context->node->parent);
7865 case XML_ATTRIBUTE_NODE: {
7866 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7867
7868 return(att->parent);
7869 }
7870 case XML_DOCUMENT_NODE:
7871 case XML_DOCUMENT_TYPE_NODE:
7872 case XML_DOCUMENT_FRAG_NODE:
7873 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007874#ifdef LIBXML_DOCB_ENABLED
7875 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007876#endif
7877 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007878 case XML_NAMESPACE_DECL: {
7879 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007880
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007881 if ((ns->next != NULL) &&
7882 (ns->next->type != XML_NAMESPACE_DECL))
7883 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00007884 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007885 }
Owen Taylor3473f882001-02-23 17:55:21 +00007886 }
7887 }
7888 return(NULL);
7889}
7890
7891/**
7892 * xmlXPathNextAncestor:
7893 * @ctxt: the XPath Parser context
7894 * @cur: the current node in the traversal
7895 *
7896 * Traversal function for the "ancestor" direction
7897 * the ancestor axis contains the ancestors of the context node; the ancestors
7898 * of the context node consist of the parent of context node and the parent's
7899 * parent and so on; the nodes are ordered in reverse document order; thus the
7900 * parent is the first node on the axis, and the parent's parent is the second
7901 * node on the axis
7902 *
7903 * Returns the next element following that axis
7904 */
7905xmlNodePtr
7906xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007907 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007908 /*
7909 * the parent of an attribute or namespace node is the element
7910 * to which the attribute or namespace node is attached
7911 * !!!!!!!!!!!!!
7912 */
7913 if (cur == NULL) {
7914 if (ctxt->context->node == NULL) return(NULL);
7915 switch (ctxt->context->node->type) {
7916 case XML_ELEMENT_NODE:
7917 case XML_TEXT_NODE:
7918 case XML_CDATA_SECTION_NODE:
7919 case XML_ENTITY_REF_NODE:
7920 case XML_ENTITY_NODE:
7921 case XML_PI_NODE:
7922 case XML_COMMENT_NODE:
7923 case XML_DTD_NODE:
7924 case XML_ELEMENT_DECL:
7925 case XML_ATTRIBUTE_DECL:
7926 case XML_ENTITY_DECL:
7927 case XML_NOTATION_NODE:
7928 case XML_XINCLUDE_START:
7929 case XML_XINCLUDE_END:
7930 if (ctxt->context->node->parent == NULL)
7931 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007932 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007933 ((ctxt->context->node->parent->name[0] == ' ') ||
7934 (xmlStrEqual(ctxt->context->node->parent->name,
7935 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007936 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007937 return(ctxt->context->node->parent);
7938 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007939 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00007940
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007941 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00007942 }
7943 case XML_DOCUMENT_NODE:
7944 case XML_DOCUMENT_TYPE_NODE:
7945 case XML_DOCUMENT_FRAG_NODE:
7946 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007947#ifdef LIBXML_DOCB_ENABLED
7948 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007949#endif
7950 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007951 case XML_NAMESPACE_DECL: {
7952 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007953
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007954 if ((ns->next != NULL) &&
7955 (ns->next->type != XML_NAMESPACE_DECL))
7956 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00007957 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00007958 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007959 }
Owen Taylor3473f882001-02-23 17:55:21 +00007960 }
7961 return(NULL);
7962 }
7963 if (cur == ctxt->context->doc->children)
7964 return((xmlNodePtr) ctxt->context->doc);
7965 if (cur == (xmlNodePtr) ctxt->context->doc)
7966 return(NULL);
7967 switch (cur->type) {
7968 case XML_ELEMENT_NODE:
7969 case XML_TEXT_NODE:
7970 case XML_CDATA_SECTION_NODE:
7971 case XML_ENTITY_REF_NODE:
7972 case XML_ENTITY_NODE:
7973 case XML_PI_NODE:
7974 case XML_COMMENT_NODE:
7975 case XML_NOTATION_NODE:
7976 case XML_DTD_NODE:
7977 case XML_ELEMENT_DECL:
7978 case XML_ATTRIBUTE_DECL:
7979 case XML_ENTITY_DECL:
7980 case XML_XINCLUDE_START:
7981 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007982 if (cur->parent == NULL)
7983 return(NULL);
7984 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007985 ((cur->parent->name[0] == ' ') ||
7986 (xmlStrEqual(cur->parent->name,
7987 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007988 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007989 return(cur->parent);
7990 case XML_ATTRIBUTE_NODE: {
7991 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7992
7993 return(att->parent);
7994 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00007995 case XML_NAMESPACE_DECL: {
7996 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007997
Aleksey Sanindffd5c82002-05-31 04:24:13 +00007998 if ((ns->next != NULL) &&
7999 (ns->next->type != XML_NAMESPACE_DECL))
8000 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00008001 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008002 return(NULL);
8003 }
Owen Taylor3473f882001-02-23 17:55:21 +00008004 case XML_DOCUMENT_NODE:
8005 case XML_DOCUMENT_TYPE_NODE:
8006 case XML_DOCUMENT_FRAG_NODE:
8007 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00008008#ifdef LIBXML_DOCB_ENABLED
8009 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00008010#endif
8011 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008012 }
8013 return(NULL);
8014}
8015
8016/**
8017 * xmlXPathNextAncestorOrSelf:
8018 * @ctxt: the XPath Parser context
8019 * @cur: the current node in the traversal
8020 *
8021 * Traversal function for the "ancestor-or-self" direction
8022 * he ancestor-or-self axis contains the context node and ancestors of
8023 * the context node in reverse document order; thus the context node is
8024 * the first node on the axis, and the context node's parent the second;
8025 * parent here is defined the same as with the parent axis.
8026 *
8027 * Returns the next element following that axis
8028 */
8029xmlNodePtr
8030xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008031 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008032 if (cur == NULL)
8033 return(ctxt->context->node);
8034 return(xmlXPathNextAncestor(ctxt, cur));
8035}
8036
8037/**
8038 * xmlXPathNextFollowingSibling:
8039 * @ctxt: the XPath Parser context
8040 * @cur: the current node in the traversal
8041 *
8042 * Traversal function for the "following-sibling" direction
8043 * The following-sibling axis contains the following siblings of the context
8044 * node in document order.
8045 *
8046 * Returns the next element following that axis
8047 */
8048xmlNodePtr
8049xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008050 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008051 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8052 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8053 return(NULL);
8054 if (cur == (xmlNodePtr) ctxt->context->doc)
8055 return(NULL);
8056 if (cur == NULL)
8057 return(ctxt->context->node->next);
8058 return(cur->next);
8059}
8060
8061/**
8062 * xmlXPathNextPrecedingSibling:
8063 * @ctxt: the XPath Parser context
8064 * @cur: the current node in the traversal
8065 *
8066 * Traversal function for the "preceding-sibling" direction
8067 * The preceding-sibling axis contains the preceding siblings of the context
8068 * node in reverse document order; the first preceding sibling is first on the
8069 * axis; the sibling preceding that node is the second on the axis and so on.
8070 *
8071 * Returns the next element following that axis
8072 */
8073xmlNodePtr
8074xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008075 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008076 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8077 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8078 return(NULL);
8079 if (cur == (xmlNodePtr) ctxt->context->doc)
8080 return(NULL);
8081 if (cur == NULL)
8082 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008083 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8084 cur = cur->prev;
8085 if (cur == NULL)
8086 return(ctxt->context->node->prev);
8087 }
Owen Taylor3473f882001-02-23 17:55:21 +00008088 return(cur->prev);
8089}
8090
8091/**
8092 * xmlXPathNextFollowing:
8093 * @ctxt: the XPath Parser context
8094 * @cur: the current node in the traversal
8095 *
8096 * Traversal function for the "following" direction
8097 * The following axis contains all nodes in the same document as the context
8098 * node that are after the context node in document order, excluding any
8099 * descendants and excluding attribute nodes and namespace nodes; the nodes
8100 * are ordered in document order
8101 *
8102 * Returns the next element following that axis
8103 */
8104xmlNodePtr
8105xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008106 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008107 if (cur != NULL && cur->children != NULL)
8108 return cur->children ;
8109 if (cur == NULL) cur = ctxt->context->node;
8110 if (cur == NULL) return(NULL) ; /* ERROR */
8111 if (cur->next != NULL) return(cur->next) ;
8112 do {
8113 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00008114 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00008115 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8116 if (cur->next != NULL) return(cur->next);
8117 } while (cur != NULL);
8118 return(cur);
8119}
8120
8121/*
8122 * xmlXPathIsAncestor:
8123 * @ancestor: the ancestor node
8124 * @node: the current node
8125 *
8126 * Check that @ancestor is a @node's ancestor
8127 *
8128 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8129 */
8130static int
8131xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8132 if ((ancestor == NULL) || (node == NULL)) return(0);
8133 /* nodes need to be in the same document */
8134 if (ancestor->doc != node->doc) return(0);
8135 /* avoid searching if ancestor or node is the root node */
8136 if (ancestor == (xmlNodePtr) node->doc) return(1);
8137 if (node == (xmlNodePtr) ancestor->doc) return(0);
8138 while (node->parent != NULL) {
8139 if (node->parent == ancestor)
8140 return(1);
8141 node = node->parent;
8142 }
8143 return(0);
8144}
8145
8146/**
8147 * xmlXPathNextPreceding:
8148 * @ctxt: the XPath Parser context
8149 * @cur: the current node in the traversal
8150 *
8151 * Traversal function for the "preceding" direction
8152 * the preceding axis contains all nodes in the same document as the context
8153 * node that are before the context node in document order, excluding any
8154 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8155 * ordered in reverse document order
8156 *
8157 * Returns the next element following that axis
8158 */
8159xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00008160xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8161{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008162 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008163 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008164 cur = ctxt->context->node;
8165 if (cur == NULL)
8166 return (NULL);
8167 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8168 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00008169 do {
8170 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008171 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8172 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008173 }
8174
8175 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008176 if (cur == NULL)
8177 return (NULL);
8178 if (cur == ctxt->context->doc->children)
8179 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008180 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00008181 return (cur);
8182}
8183
8184/**
8185 * xmlXPathNextPrecedingInternal:
8186 * @ctxt: the XPath Parser context
8187 * @cur: the current node in the traversal
8188 *
8189 * Traversal function for the "preceding" direction
8190 * the preceding axis contains all nodes in the same document as the context
8191 * node that are before the context node in document order, excluding any
8192 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8193 * ordered in reverse document order
Daniel Veillard45490ae2008-07-29 09:13:19 +00008194 * This is a faster implementation but internal only since it requires a
Daniel Veillardf06307e2001-07-03 10:35:50 +00008195 * state kept in the parser context: ctxt->ancestor.
8196 *
8197 * Returns the next element following that axis
8198 */
8199static xmlNodePtr
8200xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8201 xmlNodePtr cur)
8202{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008203 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008204 if (cur == NULL) {
8205 cur = ctxt->context->node;
8206 if (cur == NULL)
8207 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00008208 if (cur->type == XML_NAMESPACE_DECL)
8209 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008210 ctxt->ancestor = cur->parent;
8211 }
8212 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8213 cur = cur->prev;
8214 while (cur->prev == NULL) {
8215 cur = cur->parent;
8216 if (cur == NULL)
8217 return (NULL);
8218 if (cur == ctxt->context->doc->children)
8219 return (NULL);
8220 if (cur != ctxt->ancestor)
8221 return (cur);
8222 ctxt->ancestor = cur->parent;
8223 }
8224 cur = cur->prev;
8225 while (cur->last != NULL)
8226 cur = cur->last;
8227 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008228}
8229
8230/**
8231 * xmlXPathNextNamespace:
8232 * @ctxt: the XPath Parser context
8233 * @cur: the current attribute in the traversal
8234 *
8235 * Traversal function for the "namespace" direction
8236 * the namespace axis contains the namespace nodes of the context node;
8237 * the order of nodes on this axis is implementation-defined; the axis will
8238 * be empty unless the context node is an element
8239 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008240 * We keep the XML namespace node at the end of the list.
8241 *
Owen Taylor3473f882001-02-23 17:55:21 +00008242 * Returns the next element following that axis
8243 */
8244xmlNodePtr
8245xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008246 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008247 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00008248 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008249 if (ctxt->context->tmpNsList != NULL)
8250 xmlFree(ctxt->context->tmpNsList);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008251 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00008252 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008253 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00008254 if (ctxt->context->tmpNsList != NULL) {
8255 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8256 ctxt->context->tmpNsNr++;
8257 }
8258 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008259 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008260 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00008261 if (ctxt->context->tmpNsNr > 0) {
8262 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8263 } else {
8264 if (ctxt->context->tmpNsList != NULL)
8265 xmlFree(ctxt->context->tmpNsList);
8266 ctxt->context->tmpNsList = NULL;
8267 return(NULL);
8268 }
Owen Taylor3473f882001-02-23 17:55:21 +00008269}
8270
8271/**
8272 * xmlXPathNextAttribute:
8273 * @ctxt: the XPath Parser context
8274 * @cur: the current attribute in the traversal
8275 *
8276 * Traversal function for the "attribute" direction
8277 * TODO: support DTD inherited default attributes
8278 *
8279 * Returns the next element following that axis
8280 */
8281xmlNodePtr
8282xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008283 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00008284 if (ctxt->context->node == NULL)
8285 return(NULL);
8286 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8287 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008288 if (cur == NULL) {
8289 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8290 return(NULL);
8291 return((xmlNodePtr)ctxt->context->node->properties);
8292 }
8293 return((xmlNodePtr)cur->next);
8294}
8295
8296/************************************************************************
8297 * *
8298 * NodeTest Functions *
8299 * *
8300 ************************************************************************/
8301
Owen Taylor3473f882001-02-23 17:55:21 +00008302#define IS_FUNCTION 200
8303
Owen Taylor3473f882001-02-23 17:55:21 +00008304
8305/************************************************************************
8306 * *
8307 * Implicit tree core function library *
8308 * *
8309 ************************************************************************/
8310
8311/**
8312 * xmlXPathRoot:
8313 * @ctxt: the XPath Parser context
8314 *
8315 * Initialize the context to the root of the document
8316 */
8317void
8318xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008319 if ((ctxt == NULL) || (ctxt->context == NULL))
8320 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008321 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008322 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8323 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008324}
8325
8326/************************************************************************
8327 * *
8328 * The explicit core function library *
8329 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8330 * *
8331 ************************************************************************/
8332
8333
8334/**
8335 * xmlXPathLastFunction:
8336 * @ctxt: the XPath Parser context
8337 * @nargs: the number of arguments
8338 *
8339 * Implement the last() XPath function
8340 * number last()
8341 * The last function returns the number of nodes in the context node list.
8342 */
8343void
8344xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8345 CHECK_ARITY(0);
8346 if (ctxt->context->contextSize >= 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008347 valuePush(ctxt,
8348 xmlXPathCacheNewFloat(ctxt->context,
8349 (double) ctxt->context->contextSize));
Owen Taylor3473f882001-02-23 17:55:21 +00008350#ifdef DEBUG_EXPR
8351 xmlGenericError(xmlGenericErrorContext,
8352 "last() : %d\n", ctxt->context->contextSize);
8353#endif
8354 } else {
8355 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8356 }
8357}
8358
8359/**
8360 * xmlXPathPositionFunction:
8361 * @ctxt: the XPath Parser context
8362 * @nargs: the number of arguments
8363 *
8364 * Implement the position() XPath function
8365 * number position()
8366 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008367 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00008368 * will be equal to last().
8369 */
8370void
8371xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8372 CHECK_ARITY(0);
8373 if (ctxt->context->proximityPosition >= 0) {
8374 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008375 xmlXPathCacheNewFloat(ctxt->context,
8376 (double) ctxt->context->proximityPosition));
Owen Taylor3473f882001-02-23 17:55:21 +00008377#ifdef DEBUG_EXPR
8378 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8379 ctxt->context->proximityPosition);
8380#endif
8381 } else {
8382 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8383 }
8384}
8385
8386/**
8387 * xmlXPathCountFunction:
8388 * @ctxt: the XPath Parser context
8389 * @nargs: the number of arguments
8390 *
8391 * Implement the count() XPath function
8392 * number count(node-set)
8393 */
8394void
8395xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8396 xmlXPathObjectPtr cur;
8397
8398 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008399 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008400 ((ctxt->value->type != XPATH_NODESET) &&
8401 (ctxt->value->type != XPATH_XSLT_TREE)))
8402 XP_ERROR(XPATH_INVALID_TYPE);
8403 cur = valuePop(ctxt);
8404
Daniel Veillard911f49a2001-04-07 15:39:35 +00008405 if ((cur == NULL) || (cur->nodesetval == NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008406 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00008407 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008408 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8409 (double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00008410 } else {
8411 if ((cur->nodesetval->nodeNr != 1) ||
8412 (cur->nodesetval->nodeTab == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008413 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00008414 } else {
8415 xmlNodePtr tmp;
8416 int i = 0;
8417
8418 tmp = cur->nodesetval->nodeTab[0];
8419 if (tmp != NULL) {
8420 tmp = tmp->children;
8421 while (tmp != NULL) {
8422 tmp = tmp->next;
8423 i++;
8424 }
8425 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008426 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
Daniel Veillardfe703322001-08-14 12:18:09 +00008427 }
8428 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008429 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008430}
8431
8432/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008433 * xmlXPathGetElementsByIds:
8434 * @doc: the document
8435 * @ids: a whitespace separated list of IDs
8436 *
8437 * Selects elements by their unique ID.
8438 *
8439 * Returns a node-set of selected elements.
8440 */
8441static xmlNodeSetPtr
8442xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8443 xmlNodeSetPtr ret;
8444 const xmlChar *cur = ids;
8445 xmlChar *ID;
8446 xmlAttrPtr attr;
8447 xmlNodePtr elem = NULL;
8448
Daniel Veillard7a985a12003-07-06 17:57:42 +00008449 if (ids == NULL) return(NULL);
8450
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008451 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00008452 if (ret == NULL)
8453 return(ret);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008454
William M. Brack76e95df2003-10-18 16:20:14 +00008455 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008456 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008457 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00008458 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008459
8460 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00008461 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00008462 /*
8463 * We used to check the fact that the value passed
8464 * was an NCName, but this generated much troubles for
8465 * me and Aleksey Sanin, people blatantly violated that
8466 * constaint, like Visa3D spec.
8467 * if (xmlValidateNCName(ID, 1) == 0)
8468 */
8469 attr = xmlGetID(doc, ID);
8470 if (attr != NULL) {
8471 if (attr->type == XML_ATTRIBUTE_NODE)
8472 elem = attr->parent;
8473 else if (attr->type == XML_ELEMENT_NODE)
8474 elem = (xmlNodePtr) attr;
8475 else
8476 elem = NULL;
8477 if (elem != NULL)
8478 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00008479 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008480 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00008481 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008482
William M. Brack76e95df2003-10-18 16:20:14 +00008483 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008484 ids = cur;
8485 }
8486 return(ret);
8487}
8488
8489/**
Owen Taylor3473f882001-02-23 17:55:21 +00008490 * xmlXPathIdFunction:
8491 * @ctxt: the XPath Parser context
8492 * @nargs: the number of arguments
8493 *
8494 * Implement the id() XPath function
8495 * node-set id(object)
8496 * The id function selects elements by their unique ID
8497 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8498 * then the result is the union of the result of applying id to the
8499 * string value of each of the nodes in the argument node-set. When the
8500 * argument to id is of any other type, the argument is converted to a
8501 * string as if by a call to the string function; the string is split
8502 * into a whitespace-separated list of tokens (whitespace is any sequence
8503 * of characters matching the production S); the result is a node-set
8504 * containing the elements in the same document as the context node that
8505 * have a unique ID equal to any of the tokens in the list.
8506 */
8507void
8508xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008509 xmlChar *tokens;
8510 xmlNodeSetPtr ret;
8511 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00008512
8513 CHECK_ARITY(1);
8514 obj = valuePop(ctxt);
8515 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00008516 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008517 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00008518 int i;
8519
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008520 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00008521 /*
8522 * FIXME -- in an out-of-memory condition this will behave badly.
8523 * The solution is not clear -- we already popped an item from
8524 * ctxt, so the object is in a corrupt state.
8525 */
Owen Taylor3473f882001-02-23 17:55:21 +00008526
Daniel Veillard911f49a2001-04-07 15:39:35 +00008527 if (obj->nodesetval != NULL) {
8528 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008529 tokens =
8530 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8531 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8532 ret = xmlXPathNodeSetMerge(ret, ns);
8533 xmlXPathFreeNodeSet(ns);
8534 if (tokens != NULL)
8535 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00008536 }
Owen Taylor3473f882001-02-23 17:55:21 +00008537 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008538 xmlXPathReleaseObject(ctxt->context, obj);
8539 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00008540 return;
8541 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008542 obj = xmlXPathCacheConvertString(ctxt->context, obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008543 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008544 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008545 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00008546 return;
8547}
8548
8549/**
8550 * xmlXPathLocalNameFunction:
8551 * @ctxt: the XPath Parser context
8552 * @nargs: the number of arguments
8553 *
8554 * Implement the local-name() XPath function
8555 * string local-name(node-set?)
8556 * The local-name function returns a string containing the local part
8557 * of the name of the node in the argument node-set that is first in
8558 * document order. If the node-set is empty or the first node has no
8559 * name, an empty string is returned. If the argument is omitted it
8560 * defaults to the context node.
8561 */
8562void
8563xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8564 xmlXPathObjectPtr cur;
8565
Daniel Veillarda82b1822004-11-08 16:24:57 +00008566 if (ctxt == NULL) return;
8567
Owen Taylor3473f882001-02-23 17:55:21 +00008568 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008569 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8570 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008571 nargs = 1;
8572 }
8573
8574 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008575 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008576 ((ctxt->value->type != XPATH_NODESET) &&
8577 (ctxt->value->type != XPATH_XSLT_TREE)))
8578 XP_ERROR(XPATH_INVALID_TYPE);
8579 cur = valuePop(ctxt);
8580
Daniel Veillard911f49a2001-04-07 15:39:35 +00008581 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008582 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008583 } else {
8584 int i = 0; /* Should be first in document order !!!!! */
8585 switch (cur->nodesetval->nodeTab[i]->type) {
8586 case XML_ELEMENT_NODE:
8587 case XML_ATTRIBUTE_NODE:
8588 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008589 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008590 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008591 else
8592 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008593 xmlXPathCacheNewString(ctxt->context,
8594 cur->nodesetval->nodeTab[i]->name));
Owen Taylor3473f882001-02-23 17:55:21 +00008595 break;
8596 case XML_NAMESPACE_DECL:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008597 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008598 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8599 break;
8600 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008601 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008602 }
8603 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008604 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008605}
8606
8607/**
8608 * xmlXPathNamespaceURIFunction:
8609 * @ctxt: the XPath Parser context
8610 * @nargs: the number of arguments
8611 *
8612 * Implement the namespace-uri() XPath function
8613 * string namespace-uri(node-set?)
8614 * The namespace-uri function returns a string containing the
8615 * namespace URI of the expanded name of the node in the argument
8616 * node-set that is first in document order. If the node-set is empty,
8617 * the first node has no name, or the expanded name has no namespace
8618 * URI, an empty string is returned. If the argument is omitted it
8619 * defaults to the context node.
8620 */
8621void
8622xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8623 xmlXPathObjectPtr cur;
8624
Daniel Veillarda82b1822004-11-08 16:24:57 +00008625 if (ctxt == NULL) return;
8626
Owen Taylor3473f882001-02-23 17:55:21 +00008627 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008628 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8629 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008630 nargs = 1;
8631 }
8632 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008633 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008634 ((ctxt->value->type != XPATH_NODESET) &&
8635 (ctxt->value->type != XPATH_XSLT_TREE)))
8636 XP_ERROR(XPATH_INVALID_TYPE);
8637 cur = valuePop(ctxt);
8638
Daniel Veillard911f49a2001-04-07 15:39:35 +00008639 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008640 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008641 } else {
8642 int i = 0; /* Should be first in document order !!!!! */
8643 switch (cur->nodesetval->nodeTab[i]->type) {
8644 case XML_ELEMENT_NODE:
8645 case XML_ATTRIBUTE_NODE:
8646 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008647 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008648 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008649 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008650 cur->nodesetval->nodeTab[i]->ns->href));
8651 break;
8652 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008653 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008654 }
8655 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008656 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008657}
8658
8659/**
8660 * xmlXPathNameFunction:
8661 * @ctxt: the XPath Parser context
8662 * @nargs: the number of arguments
8663 *
8664 * Implement the name() XPath function
8665 * string name(node-set?)
8666 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008667 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00008668 * order. The QName must represent the name with respect to the namespace
8669 * declarations in effect on the node whose name is being represented.
8670 * Typically, this will be the form in which the name occurred in the XML
8671 * source. This need not be the case if there are namespace declarations
8672 * in effect on the node that associate multiple prefixes with the same
8673 * namespace. However, an implementation may include information about
8674 * the original prefix in its representation of nodes; in this case, an
8675 * implementation can ensure that the returned string is always the same
8676 * as the QName used in the XML source. If the argument it omitted it
8677 * defaults to the context node.
8678 * Libxml keep the original prefix so the "real qualified name" used is
8679 * returned.
8680 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008681static void
Daniel Veillard04383752001-07-08 14:27:15 +00008682xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8683{
Owen Taylor3473f882001-02-23 17:55:21 +00008684 xmlXPathObjectPtr cur;
8685
8686 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008687 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8688 ctxt->context->node));
Daniel Veillard04383752001-07-08 14:27:15 +00008689 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008690 }
8691
8692 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00008693 if ((ctxt->value == NULL) ||
8694 ((ctxt->value->type != XPATH_NODESET) &&
8695 (ctxt->value->type != XPATH_XSLT_TREE)))
8696 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00008697 cur = valuePop(ctxt);
8698
Daniel Veillard911f49a2001-04-07 15:39:35 +00008699 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008700 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008701 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00008702 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00008703
Daniel Veillard04383752001-07-08 14:27:15 +00008704 switch (cur->nodesetval->nodeTab[i]->type) {
8705 case XML_ELEMENT_NODE:
8706 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008707 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008708 valuePush(ctxt,
8709 xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008710 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8711 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008712 valuePush(ctxt,
8713 xmlXPathCacheNewString(ctxt->context,
8714 cur->nodesetval->nodeTab[i]->name));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008715 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00008716 xmlChar *fullname;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008717
Daniel Veillardc00cda82003-04-07 10:22:39 +00008718 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8719 cur->nodesetval->nodeTab[i]->ns->prefix,
8720 NULL, 0);
8721 if (fullname == cur->nodesetval->nodeTab[i]->name)
8722 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8723 if (fullname == NULL) {
8724 XP_ERROR(XPATH_MEMORY_ERROR);
8725 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008726 valuePush(ctxt, xmlXPathCacheWrapString(
8727 ctxt->context, fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00008728 }
8729 break;
8730 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008731 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8732 cur->nodesetval->nodeTab[i]));
Daniel Veillard04383752001-07-08 14:27:15 +00008733 xmlXPathLocalNameFunction(ctxt, 1);
8734 }
Owen Taylor3473f882001-02-23 17:55:21 +00008735 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008736 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008737}
8738
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008739
8740/**
Owen Taylor3473f882001-02-23 17:55:21 +00008741 * xmlXPathStringFunction:
8742 * @ctxt: the XPath Parser context
8743 * @nargs: the number of arguments
8744 *
8745 * Implement the string() XPath function
8746 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00008747 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00008748 * - A node-set is converted to a string by returning the value of
8749 * the node in the node-set that is first in document order.
8750 * If the node-set is empty, an empty string is returned.
8751 * - A number is converted to a string as follows
Daniel Veillard45490ae2008-07-29 09:13:19 +00008752 * + NaN is converted to the string NaN
8753 * + positive zero is converted to the string 0
8754 * + negative zero is converted to the string 0
8755 * + positive infinity is converted to the string Infinity
8756 * + negative infinity is converted to the string -Infinity
Owen Taylor3473f882001-02-23 17:55:21 +00008757 * + if the number is an integer, the number is represented in
8758 * decimal form as a Number with no decimal point and no leading
8759 * zeros, preceded by a minus sign (-) if the number is negative
8760 * + otherwise, the number is represented in decimal form as a
8761 * Number including a decimal point with at least one digit
8762 * before the decimal point and at least one digit after the
8763 * decimal point, preceded by a minus sign (-) if the number
8764 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008765 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00008766 * before the decimal point; beyond the one required digit
8767 * after the decimal point there must be as many, but only as
8768 * many, more digits as are needed to uniquely distinguish the
8769 * number from all other IEEE 754 numeric values.
8770 * - The boolean false value is converted to the string false.
8771 * The boolean true value is converted to the string true.
8772 *
8773 * If the argument is omitted, it defaults to a node-set with the
8774 * context node as its only member.
8775 */
8776void
8777xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8778 xmlXPathObjectPtr cur;
8779
Daniel Veillarda82b1822004-11-08 16:24:57 +00008780 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008781 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008782 valuePush(ctxt,
8783 xmlXPathCacheWrapString(ctxt->context,
8784 xmlXPathCastNodeToString(ctxt->context->node)));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008785 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008786 }
8787
8788 CHECK_ARITY(1);
8789 cur = valuePop(ctxt);
8790 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008791 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00008792}
8793
8794/**
8795 * xmlXPathStringLengthFunction:
8796 * @ctxt: the XPath Parser context
8797 * @nargs: the number of arguments
8798 *
8799 * Implement the string-length() XPath function
8800 * number string-length(string?)
8801 * The string-length returns the number of characters in the string
8802 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8803 * the context node converted to a string, in other words the value
8804 * of the context node.
8805 */
8806void
8807xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8808 xmlXPathObjectPtr cur;
8809
8810 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008811 if ((ctxt == NULL) || (ctxt->context == NULL))
8812 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008813 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008814 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008815 } else {
8816 xmlChar *content;
8817
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008818 content = xmlXPathCastNodeToString(ctxt->context->node);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008819 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8820 xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00008821 xmlFree(content);
8822 }
8823 return;
8824 }
8825 CHECK_ARITY(1);
8826 CAST_TO_STRING;
8827 CHECK_TYPE(XPATH_STRING);
8828 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008829 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
Daniel Veillard45490ae2008-07-29 09:13:19 +00008830 xmlUTF8Strlen(cur->stringval)));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008831 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008832}
8833
8834/**
8835 * xmlXPathConcatFunction:
8836 * @ctxt: the XPath Parser context
8837 * @nargs: the number of arguments
8838 *
8839 * Implement the concat() XPath function
8840 * string concat(string, string, string*)
8841 * The concat function returns the concatenation of its arguments.
8842 */
8843void
8844xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8845 xmlXPathObjectPtr cur, newobj;
8846 xmlChar *tmp;
8847
Daniel Veillarda82b1822004-11-08 16:24:57 +00008848 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008849 if (nargs < 2) {
8850 CHECK_ARITY(2);
8851 }
8852
8853 CAST_TO_STRING;
8854 cur = valuePop(ctxt);
8855 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008856 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008857 return;
8858 }
8859 nargs--;
8860
8861 while (nargs > 0) {
8862 CAST_TO_STRING;
8863 newobj = valuePop(ctxt);
8864 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008865 xmlXPathReleaseObject(ctxt->context, newobj);
8866 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008867 XP_ERROR(XPATH_INVALID_TYPE);
8868 }
8869 tmp = xmlStrcat(newobj->stringval, cur->stringval);
8870 newobj->stringval = cur->stringval;
8871 cur->stringval = tmp;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008872 xmlXPathReleaseObject(ctxt->context, newobj);
Owen Taylor3473f882001-02-23 17:55:21 +00008873 nargs--;
8874 }
8875 valuePush(ctxt, cur);
8876}
8877
8878/**
8879 * xmlXPathContainsFunction:
8880 * @ctxt: the XPath Parser context
8881 * @nargs: the number of arguments
8882 *
8883 * Implement the contains() XPath function
8884 * boolean contains(string, string)
8885 * The contains function returns true if the first argument string
8886 * contains the second argument string, and otherwise returns false.
8887 */
8888void
8889xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8890 xmlXPathObjectPtr hay, needle;
8891
8892 CHECK_ARITY(2);
8893 CAST_TO_STRING;
8894 CHECK_TYPE(XPATH_STRING);
8895 needle = valuePop(ctxt);
8896 CAST_TO_STRING;
8897 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008898
Owen Taylor3473f882001-02-23 17:55:21 +00008899 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008900 xmlXPathReleaseObject(ctxt->context, hay);
8901 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008902 XP_ERROR(XPATH_INVALID_TYPE);
8903 }
8904 if (xmlStrstr(hay->stringval, needle->stringval))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008905 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00008906 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008907 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8908 xmlXPathReleaseObject(ctxt->context, hay);
8909 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008910}
8911
8912/**
8913 * xmlXPathStartsWithFunction:
8914 * @ctxt: the XPath Parser context
8915 * @nargs: the number of arguments
8916 *
8917 * Implement the starts-with() XPath function
8918 * boolean starts-with(string, string)
8919 * The starts-with function returns true if the first argument string
8920 * starts with the second argument string, and otherwise returns false.
8921 */
8922void
8923xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8924 xmlXPathObjectPtr hay, needle;
8925 int n;
8926
8927 CHECK_ARITY(2);
8928 CAST_TO_STRING;
8929 CHECK_TYPE(XPATH_STRING);
8930 needle = valuePop(ctxt);
8931 CAST_TO_STRING;
8932 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008933
Owen Taylor3473f882001-02-23 17:55:21 +00008934 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008935 xmlXPathReleaseObject(ctxt->context, hay);
8936 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008937 XP_ERROR(XPATH_INVALID_TYPE);
8938 }
8939 n = xmlStrlen(needle->stringval);
8940 if (xmlStrncmp(hay->stringval, needle->stringval, n))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008941 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008942 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008943 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8944 xmlXPathReleaseObject(ctxt->context, hay);
8945 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008946}
8947
8948/**
8949 * xmlXPathSubstringFunction:
8950 * @ctxt: the XPath Parser context
8951 * @nargs: the number of arguments
8952 *
8953 * Implement the substring() XPath function
8954 * string substring(string, number, number?)
8955 * The substring function returns the substring of the first argument
8956 * starting at the position specified in the second argument with
8957 * length specified in the third argument. For example,
8958 * substring("12345",2,3) returns "234". If the third argument is not
8959 * specified, it returns the substring starting at the position specified
8960 * in the second argument and continuing to the end of the string. For
8961 * example, substring("12345",2) returns "2345". More precisely, each
8962 * character in the string (see [3.6 Strings]) is considered to have a
8963 * numeric position: the position of the first character is 1, the position
8964 * of the second character is 2 and so on. The returned substring contains
8965 * those characters for which the position of the character is greater than
8966 * or equal to the second argument and, if the third argument is specified,
8967 * less than the sum of the second and third arguments; the comparisons
8968 * and addition used for the above follow the standard IEEE 754 rules. Thus:
Daniel Veillard45490ae2008-07-29 09:13:19 +00008969 * - substring("12345", 1.5, 2.6) returns "234"
8970 * - substring("12345", 0, 3) returns "12"
8971 * - substring("12345", 0 div 0, 3) returns ""
8972 * - substring("12345", 1, 0 div 0) returns ""
8973 * - substring("12345", -42, 1 div 0) returns "12345"
8974 * - substring("12345", -1 div 0, 1 div 0) returns ""
Owen Taylor3473f882001-02-23 17:55:21 +00008975 */
8976void
8977xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8978 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00008979 double le=0, in;
8980 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00008981 xmlChar *ret;
8982
Owen Taylor3473f882001-02-23 17:55:21 +00008983 if (nargs < 2) {
8984 CHECK_ARITY(2);
8985 }
8986 if (nargs > 3) {
8987 CHECK_ARITY(3);
8988 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008989 /*
8990 * take care of possible last (position) argument
8991 */
Owen Taylor3473f882001-02-23 17:55:21 +00008992 if (nargs == 3) {
8993 CAST_TO_NUMBER;
8994 CHECK_TYPE(XPATH_NUMBER);
8995 len = valuePop(ctxt);
8996 le = len->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008997 xmlXPathReleaseObject(ctxt->context, len);
Owen Taylor3473f882001-02-23 17:55:21 +00008998 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008999
Owen Taylor3473f882001-02-23 17:55:21 +00009000 CAST_TO_NUMBER;
9001 CHECK_TYPE(XPATH_NUMBER);
9002 start = valuePop(ctxt);
9003 in = start->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009004 xmlXPathReleaseObject(ctxt->context, start);
Owen Taylor3473f882001-02-23 17:55:21 +00009005 CAST_TO_STRING;
9006 CHECK_TYPE(XPATH_STRING);
9007 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00009008 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00009009
Daniel Veillard97ac1312001-05-30 19:14:17 +00009010 /*
9011 * If last pos not present, calculate last position
9012 */
Daniel Veillard9e412302002-06-10 15:59:44 +00009013 if (nargs != 3) {
9014 le = (double)m;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009015 if (in < 1.0)
Daniel Veillard9e412302002-06-10 15:59:44 +00009016 in = 1.0;
9017 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009018
Daniel Veillard45490ae2008-07-29 09:13:19 +00009019 /* Need to check for the special cases where either
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009020 * the index is NaN, the length is NaN, or both
9021 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00009022 */
Daniel Veillard9e412302002-06-10 15:59:44 +00009023 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009024 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00009025 * To meet the requirements of the spec, the arguments
Daniel Veillard45490ae2008-07-29 09:13:19 +00009026 * must be converted to integer format before
Daniel Veillard9e412302002-06-10 15:59:44 +00009027 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009028 *
Daniel Veillard9e412302002-06-10 15:59:44 +00009029 * First we go to integer form, rounding up
9030 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009031 */
9032 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00009033 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00009034
Daniel Veillard9e412302002-06-10 15:59:44 +00009035 if (xmlXPathIsInf(le) == 1) {
9036 l = m;
9037 if (i < 1)
9038 i = 1;
9039 }
9040 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9041 l = 0;
9042 else {
9043 l = (int) le;
9044 if (((double)l)+0.5 <= le) l++;
9045 }
9046
9047 /* Now we normalize inidices */
9048 i -= 1;
9049 l += i;
9050 if (i < 0)
9051 i = 0;
9052 if (l > m)
9053 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00009054
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009055 /* number of chars to copy */
9056 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00009057
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009058 ret = xmlUTF8Strsub(str->stringval, i, l);
9059 }
9060 else {
9061 ret = NULL;
9062 }
Owen Taylor3473f882001-02-23 17:55:21 +00009063 if (ret == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009064 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00009065 else {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009066 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009067 xmlFree(ret);
9068 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009069 xmlXPathReleaseObject(ctxt->context, str);
Owen Taylor3473f882001-02-23 17:55:21 +00009070}
9071
9072/**
9073 * xmlXPathSubstringBeforeFunction:
9074 * @ctxt: the XPath Parser context
9075 * @nargs: the number of arguments
9076 *
9077 * Implement the substring-before() XPath function
9078 * string substring-before(string, string)
9079 * The substring-before function returns the substring of the first
9080 * argument string that precedes the first occurrence of the second
9081 * argument string in the first argument string, or the empty string
9082 * if the first argument string does not contain the second argument
9083 * string. For example, substring-before("1999/04/01","/") returns 1999.
9084 */
9085void
9086xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9087 xmlXPathObjectPtr str;
9088 xmlXPathObjectPtr find;
9089 xmlBufferPtr target;
9090 const xmlChar *point;
9091 int offset;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009092
Owen Taylor3473f882001-02-23 17:55:21 +00009093 CHECK_ARITY(2);
9094 CAST_TO_STRING;
9095 find = valuePop(ctxt);
9096 CAST_TO_STRING;
9097 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009098
Owen Taylor3473f882001-02-23 17:55:21 +00009099 target = xmlBufferCreate();
9100 if (target) {
9101 point = xmlStrstr(str->stringval, find->stringval);
9102 if (point) {
9103 offset = (int)(point - str->stringval);
9104 xmlBufferAdd(target, str->stringval, offset);
9105 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009106 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9107 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00009108 xmlBufferFree(target);
9109 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009110 xmlXPathReleaseObject(ctxt->context, str);
9111 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009112}
9113
9114/**
9115 * xmlXPathSubstringAfterFunction:
9116 * @ctxt: the XPath Parser context
9117 * @nargs: the number of arguments
9118 *
9119 * Implement the substring-after() XPath function
9120 * string substring-after(string, string)
9121 * The substring-after function returns the substring of the first
9122 * argument string that follows the first occurrence of the second
9123 * argument string in the first argument string, or the empty stringi
9124 * if the first argument string does not contain the second argument
9125 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9126 * and substring-after("1999/04/01","19") returns 99/04/01.
9127 */
9128void
9129xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9130 xmlXPathObjectPtr str;
9131 xmlXPathObjectPtr find;
9132 xmlBufferPtr target;
9133 const xmlChar *point;
9134 int offset;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009135
Owen Taylor3473f882001-02-23 17:55:21 +00009136 CHECK_ARITY(2);
9137 CAST_TO_STRING;
9138 find = valuePop(ctxt);
9139 CAST_TO_STRING;
9140 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009141
Owen Taylor3473f882001-02-23 17:55:21 +00009142 target = xmlBufferCreate();
9143 if (target) {
9144 point = xmlStrstr(str->stringval, find->stringval);
9145 if (point) {
9146 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9147 xmlBufferAdd(target, &str->stringval[offset],
9148 xmlStrlen(str->stringval) - offset);
9149 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009150 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillard45490ae2008-07-29 09:13:19 +00009151 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00009152 xmlBufferFree(target);
9153 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009154 xmlXPathReleaseObject(ctxt->context, str);
9155 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009156}
9157
9158/**
9159 * xmlXPathNormalizeFunction:
9160 * @ctxt: the XPath Parser context
9161 * @nargs: the number of arguments
9162 *
9163 * Implement the normalize-space() XPath function
9164 * string normalize-space(string?)
9165 * The normalize-space function returns the argument string with white
9166 * space normalized by stripping leading and trailing whitespace
9167 * and replacing sequences of whitespace characters by a single
9168 * space. Whitespace characters are the same allowed by the S production
9169 * in XML. If the argument is omitted, it defaults to the context
9170 * node converted to a string, in other words the value of the context node.
9171 */
9172void
9173xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9174 xmlXPathObjectPtr obj = NULL;
9175 xmlChar *source = NULL;
9176 xmlBufferPtr target;
9177 xmlChar blank;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009178
Daniel Veillarda82b1822004-11-08 16:24:57 +00009179 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009180 if (nargs == 0) {
9181 /* Use current context node */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009182 valuePush(ctxt,
9183 xmlXPathCacheWrapString(ctxt->context,
9184 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00009185 nargs = 1;
9186 }
9187
9188 CHECK_ARITY(1);
9189 CAST_TO_STRING;
9190 CHECK_TYPE(XPATH_STRING);
9191 obj = valuePop(ctxt);
9192 source = obj->stringval;
9193
9194 target = xmlBufferCreate();
9195 if (target && source) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00009196
Owen Taylor3473f882001-02-23 17:55:21 +00009197 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00009198 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00009199 source++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009200
Owen Taylor3473f882001-02-23 17:55:21 +00009201 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9202 blank = 0;
9203 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00009204 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009205 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00009206 } else {
9207 if (blank) {
9208 xmlBufferAdd(target, &blank, 1);
9209 blank = 0;
9210 }
9211 xmlBufferAdd(target, source, 1);
9212 }
9213 source++;
9214 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009215 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9216 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00009217 xmlBufferFree(target);
9218 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009219 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00009220}
9221
9222/**
9223 * xmlXPathTranslateFunction:
9224 * @ctxt: the XPath Parser context
9225 * @nargs: the number of arguments
9226 *
9227 * Implement the translate() XPath function
9228 * string translate(string, string, string)
9229 * The translate function returns the first argument string with
9230 * occurrences of characters in the second argument string replaced
9231 * by the character at the corresponding position in the third argument
9232 * string. For example, translate("bar","abc","ABC") returns the string
9233 * BAr. If there is a character in the second argument string with no
9234 * character at a corresponding position in the third argument string
9235 * (because the second argument string is longer than the third argument
9236 * string), then occurrences of that character in the first argument
9237 * string are removed. For example, translate("--aaa--","abc-","ABC")
9238 * returns "AAA". If a character occurs more than once in second
9239 * argument string, then the first occurrence determines the replacement
9240 * character. If the third argument string is longer than the second
9241 * argument string, then excess characters are ignored.
9242 */
9243void
9244xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00009245 xmlXPathObjectPtr str;
9246 xmlXPathObjectPtr from;
9247 xmlXPathObjectPtr to;
9248 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009249 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009250 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00009251 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009252 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00009253
Daniel Veillarde043ee12001-04-16 14:08:07 +00009254 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00009255
Daniel Veillarde043ee12001-04-16 14:08:07 +00009256 CAST_TO_STRING;
9257 to = valuePop(ctxt);
9258 CAST_TO_STRING;
9259 from = valuePop(ctxt);
9260 CAST_TO_STRING;
9261 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009262
Daniel Veillarde043ee12001-04-16 14:08:07 +00009263 target = xmlBufferCreate();
9264 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009265 max = xmlUTF8Strlen(to->stringval);
9266 for (cptr = str->stringval; (ch=*cptr); ) {
9267 offset = xmlUTF8Strloc(from->stringval, cptr);
9268 if (offset >= 0) {
9269 if (offset < max) {
9270 point = xmlUTF8Strpos(to->stringval, offset);
9271 if (point)
9272 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
9273 }
9274 } else
9275 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9276
9277 /* Step to next character in input */
9278 cptr++;
9279 if ( ch & 0x80 ) {
9280 /* if not simple ascii, verify proper format */
9281 if ( (ch & 0xc0) != 0xc0 ) {
9282 xmlGenericError(xmlGenericErrorContext,
9283 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9284 break;
9285 }
9286 /* then skip over remaining bytes for this char */
9287 while ( (ch <<= 1) & 0x80 )
9288 if ( (*cptr++ & 0xc0) != 0x80 ) {
9289 xmlGenericError(xmlGenericErrorContext,
9290 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9291 break;
9292 }
9293 if (ch & 0x80) /* must have had error encountered */
9294 break;
9295 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00009296 }
Owen Taylor3473f882001-02-23 17:55:21 +00009297 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009298 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9299 xmlBufferContent(target)));
Daniel Veillarde043ee12001-04-16 14:08:07 +00009300 xmlBufferFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009301 xmlXPathReleaseObject(ctxt->context, str);
9302 xmlXPathReleaseObject(ctxt->context, from);
9303 xmlXPathReleaseObject(ctxt->context, to);
Owen Taylor3473f882001-02-23 17:55:21 +00009304}
9305
9306/**
9307 * xmlXPathBooleanFunction:
9308 * @ctxt: the XPath Parser context
9309 * @nargs: the number of arguments
9310 *
9311 * Implement the boolean() XPath function
9312 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00009313 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00009314 * - a number is true if and only if it is neither positive or
9315 * negative zero nor NaN
9316 * - a node-set is true if and only if it is non-empty
9317 * - a string is true if and only if its length is non-zero
9318 */
9319void
9320xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9321 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00009322
9323 CHECK_ARITY(1);
9324 cur = valuePop(ctxt);
9325 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009326 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009327 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009328}
9329
9330/**
9331 * xmlXPathNotFunction:
9332 * @ctxt: the XPath Parser context
9333 * @nargs: the number of arguments
9334 *
9335 * Implement the not() XPath function
9336 * boolean not(boolean)
9337 * The not function returns true if its argument is false,
9338 * and false otherwise.
9339 */
9340void
9341xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9342 CHECK_ARITY(1);
9343 CAST_TO_BOOLEAN;
9344 CHECK_TYPE(XPATH_BOOLEAN);
9345 ctxt->value->boolval = ! ctxt->value->boolval;
9346}
9347
9348/**
9349 * xmlXPathTrueFunction:
9350 * @ctxt: the XPath Parser context
9351 * @nargs: the number of arguments
9352 *
9353 * Implement the true() XPath function
9354 * boolean true()
9355 */
9356void
9357xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9358 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009359 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009360}
9361
9362/**
9363 * xmlXPathFalseFunction:
9364 * @ctxt: the XPath Parser context
9365 * @nargs: the number of arguments
9366 *
9367 * Implement the false() XPath function
9368 * boolean false()
9369 */
9370void
9371xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9372 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009373 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009374}
9375
9376/**
9377 * xmlXPathLangFunction:
9378 * @ctxt: the XPath Parser context
9379 * @nargs: the number of arguments
9380 *
9381 * Implement the lang() XPath function
9382 * boolean lang(string)
9383 * The lang function returns true or false depending on whether the
9384 * language of the context node as specified by xml:lang attributes
9385 * is the same as or is a sublanguage of the language specified by
9386 * the argument string. The language of the context node is determined
9387 * by the value of the xml:lang attribute on the context node, or, if
9388 * the context node has no xml:lang attribute, by the value of the
9389 * xml:lang attribute on the nearest ancestor of the context node that
9390 * has an xml:lang attribute. If there is no such attribute, then lang
9391 * returns false. If there is such an attribute, then lang returns
9392 * true if the attribute value is equal to the argument ignoring case,
9393 * or if there is some suffix starting with - such that the attribute
9394 * value is equal to the argument ignoring that suffix of the attribute
9395 * value and ignoring case.
9396 */
9397void
9398xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009399 xmlXPathObjectPtr val = NULL;
9400 const xmlChar *theLang = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009401 const xmlChar *lang;
9402 int ret = 0;
9403 int i;
9404
9405 CHECK_ARITY(1);
9406 CAST_TO_STRING;
9407 CHECK_TYPE(XPATH_STRING);
9408 val = valuePop(ctxt);
9409 lang = val->stringval;
9410 theLang = xmlNodeGetLang(ctxt->context->node);
9411 if ((theLang != NULL) && (lang != NULL)) {
9412 for (i = 0;lang[i] != 0;i++)
9413 if (toupper(lang[i]) != toupper(theLang[i]))
9414 goto not_equal;
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009415 if ((theLang[i] == 0) || (theLang[i] == '-'))
9416 ret = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009417 }
9418not_equal:
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009419 if (theLang != NULL)
9420 xmlFree((void *)theLang);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009421
9422 xmlXPathReleaseObject(ctxt->context, val);
9423 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009424}
9425
9426/**
9427 * xmlXPathNumberFunction:
9428 * @ctxt: the XPath Parser context
9429 * @nargs: the number of arguments
9430 *
9431 * Implement the number() XPath function
9432 * number number(object?)
9433 */
9434void
9435xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9436 xmlXPathObjectPtr cur;
9437 double res;
9438
Daniel Veillarda82b1822004-11-08 16:24:57 +00009439 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009440 if (nargs == 0) {
9441 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009442 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
Owen Taylor3473f882001-02-23 17:55:21 +00009443 } else {
9444 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9445
9446 res = xmlXPathStringEvalNumber(content);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009447 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
Owen Taylor3473f882001-02-23 17:55:21 +00009448 xmlFree(content);
9449 }
9450 return;
9451 }
9452
9453 CHECK_ARITY(1);
9454 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009455 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00009456}
9457
9458/**
9459 * xmlXPathSumFunction:
9460 * @ctxt: the XPath Parser context
9461 * @nargs: the number of arguments
9462 *
9463 * Implement the sum() XPath function
9464 * number sum(node-set)
9465 * The sum function returns the sum of the values of the nodes in
9466 * the argument node-set.
9467 */
9468void
9469xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9470 xmlXPathObjectPtr cur;
9471 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009472 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00009473
9474 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009475 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009476 ((ctxt->value->type != XPATH_NODESET) &&
9477 (ctxt->value->type != XPATH_XSLT_TREE)))
9478 XP_ERROR(XPATH_INVALID_TYPE);
9479 cur = valuePop(ctxt);
9480
William M. Brack08171912003-12-29 02:52:11 +00009481 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009482 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9483 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00009484 }
9485 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009486 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9487 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009488}
9489
William M. Brack3d426662005-04-19 14:40:28 +00009490/*
9491 * To assure working code on multiple platforms, we want to only depend
9492 * upon the characteristic truncation of converting a floating point value
9493 * to an integer. Unfortunately, because of the different storage sizes
9494 * of our internal floating point value (double) and integer (int), we
9495 * can't directly convert (see bug 301162). This macro is a messy
9496 * 'workaround'
9497 */
9498#define XTRUNC(f, v) \
9499 f = fmod((v), INT_MAX); \
9500 f = (v) - (f) + (double)((int)(f));
9501
Owen Taylor3473f882001-02-23 17:55:21 +00009502/**
9503 * xmlXPathFloorFunction:
9504 * @ctxt: the XPath Parser context
9505 * @nargs: the number of arguments
9506 *
9507 * Implement the floor() XPath function
9508 * number floor(number)
9509 * The floor function returns the largest (closest to positive infinity)
9510 * number that is not greater than the argument and that is an integer.
9511 */
9512void
9513xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009514 double f;
9515
Owen Taylor3473f882001-02-23 17:55:21 +00009516 CHECK_ARITY(1);
9517 CAST_TO_NUMBER;
9518 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009519
William M. Brack3d426662005-04-19 14:40:28 +00009520 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009521 if (f != ctxt->value->floatval) {
9522 if (ctxt->value->floatval > 0)
9523 ctxt->value->floatval = f;
9524 else
9525 ctxt->value->floatval = f - 1;
9526 }
Owen Taylor3473f882001-02-23 17:55:21 +00009527}
9528
9529/**
9530 * xmlXPathCeilingFunction:
9531 * @ctxt: the XPath Parser context
9532 * @nargs: the number of arguments
9533 *
9534 * Implement the ceiling() XPath function
9535 * number ceiling(number)
9536 * The ceiling function returns the smallest (closest to negative infinity)
9537 * number that is not less than the argument and that is an integer.
9538 */
9539void
9540xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9541 double f;
9542
9543 CHECK_ARITY(1);
9544 CAST_TO_NUMBER;
9545 CHECK_TYPE(XPATH_NUMBER);
9546
9547#if 0
9548 ctxt->value->floatval = ceil(ctxt->value->floatval);
9549#else
William M. Brack3d426662005-04-19 14:40:28 +00009550 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009551 if (f != ctxt->value->floatval) {
9552 if (ctxt->value->floatval > 0)
9553 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009554 else {
9555 if (ctxt->value->floatval < 0 && f == 0)
9556 ctxt->value->floatval = xmlXPathNZERO;
9557 else
9558 ctxt->value->floatval = f;
9559 }
9560
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009561 }
Owen Taylor3473f882001-02-23 17:55:21 +00009562#endif
9563}
9564
9565/**
9566 * xmlXPathRoundFunction:
9567 * @ctxt: the XPath Parser context
9568 * @nargs: the number of arguments
9569 *
9570 * Implement the round() XPath function
9571 * number round(number)
9572 * The round function returns the number that is closest to the
9573 * argument and that is an integer. If there are two such numbers,
9574 * then the one that is even is returned.
9575 */
9576void
9577xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9578 double f;
9579
9580 CHECK_ARITY(1);
9581 CAST_TO_NUMBER;
9582 CHECK_TYPE(XPATH_NUMBER);
9583
Daniel Veillardcda96922001-08-21 10:56:31 +00009584 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9585 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9586 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009587 (ctxt->value->floatval == 0.0))
9588 return;
9589
William M. Brack3d426662005-04-19 14:40:28 +00009590 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009591 if (ctxt->value->floatval < 0) {
9592 if (ctxt->value->floatval < f - 0.5)
9593 ctxt->value->floatval = f - 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009594 else
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009595 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009596 if (ctxt->value->floatval == 0)
9597 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009598 } else {
9599 if (ctxt->value->floatval < f + 0.5)
9600 ctxt->value->floatval = f;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009601 else
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009602 ctxt->value->floatval = f + 1;
9603 }
Owen Taylor3473f882001-02-23 17:55:21 +00009604}
9605
9606/************************************************************************
9607 * *
9608 * The Parser *
9609 * *
9610 ************************************************************************/
9611
9612/*
William M. Brack08171912003-12-29 02:52:11 +00009613 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00009614 * implementation.
9615 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009616static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009617static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009618static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009619static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00009620static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9621 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00009622
9623/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00009624 * xmlXPathCurrentChar:
9625 * @ctxt: the XPath parser context
9626 * @cur: pointer to the beginning of the char
9627 * @len: pointer to the length of the char read
9628 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009629 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00009630 * bytes in the input buffer.
9631 *
Daniel Veillard60087f32001-10-10 09:45:09 +00009632 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00009633 */
9634
9635static int
9636xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9637 unsigned char c;
9638 unsigned int val;
9639 const xmlChar *cur;
9640
9641 if (ctxt == NULL)
9642 return(0);
9643 cur = ctxt->cur;
9644
9645 /*
9646 * We are supposed to handle UTF8, check it's valid
9647 * From rfc2044: encoding of the Unicode values on UTF-8:
9648 *
9649 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9650 * 0000 0000-0000 007F 0xxxxxxx
9651 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
Daniel Veillard45490ae2008-07-29 09:13:19 +00009652 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
Daniel Veillard61d80a22001-04-27 17:13:01 +00009653 *
9654 * Check for the 0x110000 limit too
9655 */
9656 c = *cur;
9657 if (c & 0x80) {
9658 if ((cur[1] & 0xc0) != 0x80)
9659 goto encoding_error;
9660 if ((c & 0xe0) == 0xe0) {
9661
9662 if ((cur[2] & 0xc0) != 0x80)
9663 goto encoding_error;
9664 if ((c & 0xf0) == 0xf0) {
9665 if (((c & 0xf8) != 0xf0) ||
9666 ((cur[3] & 0xc0) != 0x80))
9667 goto encoding_error;
9668 /* 4-byte code */
9669 *len = 4;
9670 val = (cur[0] & 0x7) << 18;
9671 val |= (cur[1] & 0x3f) << 12;
9672 val |= (cur[2] & 0x3f) << 6;
9673 val |= cur[3] & 0x3f;
9674 } else {
9675 /* 3-byte code */
9676 *len = 3;
9677 val = (cur[0] & 0xf) << 12;
9678 val |= (cur[1] & 0x3f) << 6;
9679 val |= cur[2] & 0x3f;
9680 }
9681 } else {
9682 /* 2-byte code */
9683 *len = 2;
9684 val = (cur[0] & 0x1f) << 6;
9685 val |= cur[1] & 0x3f;
9686 }
9687 if (!IS_CHAR(val)) {
9688 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009689 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00009690 return(val);
9691 } else {
9692 /* 1-byte code */
9693 *len = 1;
9694 return((int) *cur);
9695 }
9696encoding_error:
9697 /*
William M. Brack08171912003-12-29 02:52:11 +00009698 * If we detect an UTF8 error that probably means that the
9699 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00009700 * declaration header. Report the error and switch the encoding
9701 * to ISO-Latin-1 (if you don't like this policy, just declare the
9702 * encoding !)
9703 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00009704 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00009705 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009706}
9707
9708/**
Owen Taylor3473f882001-02-23 17:55:21 +00009709 * xmlXPathParseNCName:
9710 * @ctxt: the XPath Parser context
9711 *
9712 * parse an XML namespace non qualified name.
9713 *
9714 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9715 *
9716 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9717 * CombiningChar | Extender
9718 *
9719 * Returns the namespace name or NULL
9720 */
9721
9722xmlChar *
9723xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00009724 const xmlChar *in;
9725 xmlChar *ret;
9726 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009727
Daniel Veillarda82b1822004-11-08 16:24:57 +00009728 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00009729 /*
9730 * Accelerator for simple ASCII names
9731 */
9732 in = ctxt->cur;
9733 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9734 ((*in >= 0x41) && (*in <= 0x5A)) ||
9735 (*in == '_')) {
9736 in++;
9737 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9738 ((*in >= 0x41) && (*in <= 0x5A)) ||
9739 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00009740 (*in == '_') || (*in == '.') ||
9741 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00009742 in++;
9743 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9744 (*in == '[') || (*in == ']') || (*in == ':') ||
9745 (*in == '@') || (*in == '*')) {
9746 count = in - ctxt->cur;
9747 if (count == 0)
9748 return(NULL);
9749 ret = xmlStrndup(ctxt->cur, count);
9750 ctxt->cur = in;
9751 return(ret);
9752 }
9753 }
9754 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009755}
9756
Daniel Veillard2156a562001-04-28 12:24:34 +00009757
Owen Taylor3473f882001-02-23 17:55:21 +00009758/**
9759 * xmlXPathParseQName:
9760 * @ctxt: the XPath Parser context
Daniel Veillard45490ae2008-07-29 09:13:19 +00009761 * @prefix: a xmlChar **
Owen Taylor3473f882001-02-23 17:55:21 +00009762 *
9763 * parse an XML qualified name
9764 *
9765 * [NS 5] QName ::= (Prefix ':')? LocalPart
9766 *
9767 * [NS 6] Prefix ::= NCName
9768 *
9769 * [NS 7] LocalPart ::= NCName
9770 *
9771 * Returns the function returns the local part, and prefix is updated
9772 * to get the Prefix if any.
9773 */
9774
Daniel Veillard56a4cb82001-03-24 17:00:36 +00009775static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00009776xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9777 xmlChar *ret = NULL;
9778
9779 *prefix = NULL;
9780 ret = xmlXPathParseNCName(ctxt);
Daniel Veillard074f37e2008-09-01 13:38:22 +00009781 if (ret && CUR == ':') {
Owen Taylor3473f882001-02-23 17:55:21 +00009782 *prefix = ret;
9783 NEXT;
9784 ret = xmlXPathParseNCName(ctxt);
9785 }
9786 return(ret);
9787}
9788
9789/**
9790 * xmlXPathParseName:
9791 * @ctxt: the XPath Parser context
9792 *
9793 * parse an XML name
9794 *
9795 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9796 * CombiningChar | Extender
9797 *
9798 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9799 *
9800 * Returns the namespace name or NULL
9801 */
9802
9803xmlChar *
9804xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009805 const xmlChar *in;
9806 xmlChar *ret;
9807 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009808
Daniel Veillarda82b1822004-11-08 16:24:57 +00009809 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009810 /*
9811 * Accelerator for simple ASCII names
9812 */
9813 in = ctxt->cur;
9814 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9815 ((*in >= 0x41) && (*in <= 0x5A)) ||
9816 (*in == '_') || (*in == ':')) {
9817 in++;
9818 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9819 ((*in >= 0x41) && (*in <= 0x5A)) ||
9820 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00009821 (*in == '_') || (*in == '-') ||
9822 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00009823 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00009824 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009825 count = in - ctxt->cur;
9826 ret = xmlStrndup(ctxt->cur, count);
9827 ctxt->cur = in;
9828 return(ret);
9829 }
9830 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009831 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009832}
9833
Daniel Veillard61d80a22001-04-27 17:13:01 +00009834static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00009835xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009836 xmlChar buf[XML_MAX_NAMELEN + 5];
9837 int len = 0, l;
9838 int c;
9839
9840 /*
9841 * Handler for more complex cases
9842 */
9843 c = CUR_CHAR(l);
9844 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00009845 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9846 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00009847 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00009848 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009849 return(NULL);
9850 }
9851
9852 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9853 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9854 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00009855 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009856 (IS_COMBINING(c)) ||
9857 (IS_EXTENDER(c)))) {
9858 COPY_BUF(l,buf,len,c);
9859 NEXTL(l);
9860 c = CUR_CHAR(l);
9861 if (len >= XML_MAX_NAMELEN) {
9862 /*
9863 * Okay someone managed to make a huge name, so he's ready to pay
9864 * for the processing speed.
9865 */
9866 xmlChar *buffer;
9867 int max = len * 2;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009868
Daniel Veillard3c908dc2003-04-19 00:07:51 +00009869 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009870 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009871 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009872 }
9873 memcpy(buffer, buf, len);
9874 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9875 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00009876 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009877 (IS_COMBINING(c)) ||
9878 (IS_EXTENDER(c))) {
9879 if (len + 10 > max) {
9880 max *= 2;
9881 buffer = (xmlChar *) xmlRealloc(buffer,
9882 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009883 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009884 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009885 }
9886 }
9887 COPY_BUF(l,buffer,len,c);
9888 NEXTL(l);
9889 c = CUR_CHAR(l);
9890 }
9891 buffer[len] = 0;
9892 return(buffer);
9893 }
9894 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009895 if (len == 0)
9896 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009897 return(xmlStrndup(buf, len));
9898}
Daniel Veillard3cd72402002-05-13 10:33:30 +00009899
9900#define MAX_FRAC 20
9901
William M. Brack372a4452004-02-17 13:09:23 +00009902/*
9903 * These are used as divisors for the fractional part of a number.
9904 * Since the table includes 1.0 (representing '0' fractional digits),
9905 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
9906 */
9907static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +00009908 1.0, 10.0, 100.0, 1000.0, 10000.0,
9909 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
9910 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
9911 100000000000000.0,
9912 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +00009913 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +00009914};
9915
Owen Taylor3473f882001-02-23 17:55:21 +00009916/**
9917 * xmlXPathStringEvalNumber:
9918 * @str: A string to scan
9919 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00009920 * [30a] Float ::= Number ('e' Digits?)?
9921 *
Owen Taylor3473f882001-02-23 17:55:21 +00009922 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard45490ae2008-07-29 09:13:19 +00009923 * | '.' Digits
Owen Taylor3473f882001-02-23 17:55:21 +00009924 * [31] Digits ::= [0-9]+
9925 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009926 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00009927 * In complement of the Number expression, this function also handles
9928 * negative values : '-' Number.
9929 *
9930 * Returns the double value.
9931 */
9932double
9933xmlXPathStringEvalNumber(const xmlChar *str) {
9934 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00009935 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009936 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009937 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009938 int exponent = 0;
9939 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009940#ifdef __GNUC__
9941 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00009942 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009943#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00009944 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00009945 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009946 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
9947 return(xmlXPathNAN);
9948 }
9949 if (*cur == '-') {
9950 isneg = 1;
9951 cur++;
9952 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00009953
9954#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009955 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00009956 * tmp/temp is a workaround against a gcc compiler bug
9957 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009958 */
Daniel Veillard7b416132002-03-07 08:36:03 +00009959 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009960 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00009961 ret = ret * 10;
9962 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00009963 ok = 1;
9964 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00009965 temp = (double) tmp;
9966 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00009967 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00009968#else
Daniel Veillard7b416132002-03-07 08:36:03 +00009969 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009970 while ((*cur >= '0') && (*cur <= '9')) {
9971 ret = ret * 10 + (*cur - '0');
9972 ok = 1;
9973 cur++;
9974 }
9975#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009976
Owen Taylor3473f882001-02-23 17:55:21 +00009977 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00009978 int v, frac = 0;
9979 double fraction = 0;
9980
Owen Taylor3473f882001-02-23 17:55:21 +00009981 cur++;
9982 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
9983 return(xmlXPathNAN);
9984 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00009985 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
9986 v = (*cur - '0');
9987 fraction = fraction * 10 + v;
9988 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009989 cur++;
9990 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00009991 fraction /= my_pow10[frac];
9992 ret = ret + fraction;
9993 while ((*cur >= '0') && (*cur <= '9'))
9994 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009995 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00009996 if ((*cur == 'e') || (*cur == 'E')) {
9997 cur++;
9998 if (*cur == '-') {
9999 is_exponent_negative = 1;
10000 cur++;
William M. Brack99127052004-05-24 02:52:28 +000010001 } else if (*cur == '+') {
10002 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010003 }
10004 while ((*cur >= '0') && (*cur <= '9')) {
10005 exponent = exponent * 10 + (*cur - '0');
10006 cur++;
10007 }
10008 }
William M. Brack76e95df2003-10-18 16:20:14 +000010009 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010010 if (*cur != 0) return(xmlXPathNAN);
10011 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010012 if (is_exponent_negative) exponent = -exponent;
10013 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +000010014 return(ret);
10015}
10016
10017/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010018 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +000010019 * @ctxt: the XPath Parser context
10020 *
10021 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard45490ae2008-07-29 09:13:19 +000010022 * | '.' Digits
Owen Taylor3473f882001-02-23 17:55:21 +000010023 * [31] Digits ::= [0-9]+
10024 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010025 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +000010026 *
10027 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010028static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010029xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10030{
Owen Taylor3473f882001-02-23 17:55:21 +000010031 double ret = 0.0;
10032 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +000010033 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010034 int exponent = 0;
10035 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010036#ifdef __GNUC__
10037 unsigned long tmp = 0;
10038 double temp;
10039#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010040
10041 CHECK_ERROR;
10042 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10043 XP_ERROR(XPATH_NUMBER_ERROR);
10044 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010045#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010046 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010047 * tmp/temp is a workaround against a gcc compiler bug
10048 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010049 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010050 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010051 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010052 ret = ret * 10;
10053 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010054 ok = 1;
10055 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +000010056 temp = (double) tmp;
10057 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010058 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010059#else
10060 ret = 0;
10061 while ((CUR >= '0') && (CUR <= '9')) {
10062 ret = ret * 10 + (CUR - '0');
10063 ok = 1;
10064 NEXT;
10065 }
10066#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010067 if (CUR == '.') {
10068 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010069 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10070 XP_ERROR(XPATH_NUMBER_ERROR);
10071 }
10072 while ((CUR >= '0') && (CUR <= '9')) {
10073 mult /= 10;
10074 ret = ret + (CUR - '0') * mult;
10075 NEXT;
10076 }
Owen Taylor3473f882001-02-23 17:55:21 +000010077 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010078 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010079 NEXT;
10080 if (CUR == '-') {
10081 is_exponent_negative = 1;
10082 NEXT;
William M. Brack99127052004-05-24 02:52:28 +000010083 } else if (CUR == '+') {
10084 NEXT;
10085 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010086 while ((CUR >= '0') && (CUR <= '9')) {
10087 exponent = exponent * 10 + (CUR - '0');
10088 NEXT;
10089 }
10090 if (is_exponent_negative)
10091 exponent = -exponent;
10092 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +000010093 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010094 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010095 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010096}
10097
10098/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010099 * xmlXPathParseLiteral:
10100 * @ctxt: the XPath Parser context
10101 *
10102 * Parse a Literal
10103 *
10104 * [29] Literal ::= '"' [^"]* '"'
10105 * | "'" [^']* "'"
10106 *
10107 * Returns the value found or NULL in case of error
10108 */
10109static xmlChar *
10110xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10111 const xmlChar *q;
10112 xmlChar *ret = NULL;
10113
10114 if (CUR == '"') {
10115 NEXT;
10116 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010117 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010118 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010119 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010120 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010121 } else {
10122 ret = xmlStrndup(q, CUR_PTR - q);
10123 NEXT;
10124 }
10125 } else if (CUR == '\'') {
10126 NEXT;
10127 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010128 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010129 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010130 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010131 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010132 } else {
10133 ret = xmlStrndup(q, CUR_PTR - q);
10134 NEXT;
10135 }
10136 } else {
Daniel Veillard24505b02005-07-28 23:49:35 +000010137 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010138 }
10139 return(ret);
10140}
10141
10142/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010143 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +000010144 * @ctxt: the XPath Parser context
10145 *
10146 * Parse a Literal and push it on the stack.
10147 *
10148 * [29] Literal ::= '"' [^"]* '"'
10149 * | "'" [^']* "'"
10150 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010151 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +000010152 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010153static void
10154xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010155 const xmlChar *q;
10156 xmlChar *ret = NULL;
10157
10158 if (CUR == '"') {
10159 NEXT;
10160 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010161 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +000010162 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010163 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010164 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10165 } else {
10166 ret = xmlStrndup(q, CUR_PTR - q);
10167 NEXT;
10168 }
10169 } else if (CUR == '\'') {
10170 NEXT;
10171 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010172 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +000010173 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010174 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010175 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10176 } else {
10177 ret = xmlStrndup(q, CUR_PTR - q);
10178 NEXT;
10179 }
10180 } else {
10181 XP_ERROR(XPATH_START_LITERAL_ERROR);
10182 }
10183 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010184 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010185 xmlXPathCacheNewString(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010186 xmlFree(ret);
10187}
10188
10189/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010190 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +000010191 * @ctxt: the XPath Parser context
10192 *
10193 * Parse a VariableReference, evaluate it and push it on the stack.
10194 *
10195 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +000010196 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +000010197 * of any of the types that are possible for the value of an expression,
10198 * and may also be of additional types not specified here.
10199 *
10200 * Early evaluation is possible since:
10201 * The variable bindings [...] used to evaluate a subexpression are
Daniel Veillard45490ae2008-07-29 09:13:19 +000010202 * always the same as those used to evaluate the containing expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010203 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010204 * [36] VariableReference ::= '$' QName
Owen Taylor3473f882001-02-23 17:55:21 +000010205 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010206static void
10207xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010208 xmlChar *name;
10209 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010210
10211 SKIP_BLANKS;
10212 if (CUR != '$') {
10213 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10214 }
10215 NEXT;
10216 name = xmlXPathParseQName(ctxt, &prefix);
10217 if (name == NULL) {
10218 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10219 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010220 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010221 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10222 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010223 SKIP_BLANKS;
Daniel Veillardb3d14912005-09-04 20:47:39 +000010224 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10225 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
10226 }
Owen Taylor3473f882001-02-23 17:55:21 +000010227}
10228
10229/**
10230 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +000010231 * @name: a name string
10232 *
10233 * Is the name given a NodeType one.
10234 *
10235 * [38] NodeType ::= 'comment'
10236 * | 'text'
10237 * | 'processing-instruction'
10238 * | 'node'
10239 *
10240 * Returns 1 if true 0 otherwise
10241 */
10242int
10243xmlXPathIsNodeType(const xmlChar *name) {
10244 if (name == NULL)
10245 return(0);
10246
Daniel Veillard1971ee22002-01-31 20:29:19 +000010247 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +000010248 return(1);
10249 if (xmlStrEqual(name, BAD_CAST "text"))
10250 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010251 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +000010252 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010253 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +000010254 return(1);
10255 return(0);
10256}
10257
10258/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010259 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +000010260 * @ctxt: the XPath Parser context
10261 *
10262 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010263 * [17] Argument ::= Expr
Owen Taylor3473f882001-02-23 17:55:21 +000010264 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010265 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +000010266 * pushed on the stack
10267 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010268static void
10269xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010270 xmlChar *name;
10271 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010272 int nbargs = 0;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010273 int sort = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010274
10275 name = xmlXPathParseQName(ctxt, &prefix);
10276 if (name == NULL) {
Daniel Veillard074f37e2008-09-01 13:38:22 +000010277 xmlFree(prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010278 XP_ERROR(XPATH_EXPR_ERROR);
10279 }
10280 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010281#ifdef DEBUG_EXPR
10282 if (prefix == NULL)
10283 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10284 name);
10285 else
10286 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10287 prefix, name);
10288#endif
10289
Owen Taylor3473f882001-02-23 17:55:21 +000010290 if (CUR != '(') {
10291 XP_ERROR(XPATH_EXPR_ERROR);
10292 }
10293 NEXT;
10294 SKIP_BLANKS;
10295
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010296 /*
10297 * Optimization for count(): we don't need the node-set to be sorted.
10298 */
10299 if ((prefix == NULL) && (name[0] == 'c') &&
10300 xmlStrEqual(name, BAD_CAST "count"))
10301 {
10302 sort = 0;
10303 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010304 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +000010305 if (CUR != ')') {
10306 while (CUR != 0) {
10307 int op1 = ctxt->comp->last;
10308 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010309 xmlXPathCompileExpr(ctxt, sort);
Daniel Veillard074f37e2008-09-01 13:38:22 +000010310 if (ctxt->error != XPATH_EXPRESSION_OK) {
10311 xmlFree(name);
10312 xmlFree(prefix);
10313 return;
10314 }
Daniel Veillard71f9d732003-01-14 16:07:16 +000010315 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10316 nbargs++;
10317 if (CUR == ')') break;
10318 if (CUR != ',') {
10319 XP_ERROR(XPATH_EXPR_ERROR);
10320 }
10321 NEXT;
10322 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010323 }
Owen Taylor3473f882001-02-23 17:55:21 +000010324 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010325 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10326 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010327 NEXT;
10328 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010329}
10330
10331/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010332 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010333 * @ctxt: the XPath Parser context
10334 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010335 * [15] PrimaryExpr ::= VariableReference
Owen Taylor3473f882001-02-23 17:55:21 +000010336 * | '(' Expr ')'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010337 * | Literal
10338 * | Number
10339 * | FunctionCall
Owen Taylor3473f882001-02-23 17:55:21 +000010340 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010341 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010342 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010343static void
10344xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010345 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010346 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010347 else if (CUR == '(') {
10348 NEXT;
10349 SKIP_BLANKS;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010350 xmlXPathCompileExpr(ctxt, 1);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010351 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000010352 if (CUR != ')') {
10353 XP_ERROR(XPATH_EXPR_ERROR);
10354 }
10355 NEXT;
10356 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010357 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010358 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010359 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010360 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010361 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010362 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010363 }
10364 SKIP_BLANKS;
10365}
10366
10367/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010368 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010369 * @ctxt: the XPath Parser context
10370 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010371 * [20] FilterExpr ::= PrimaryExpr
10372 * | FilterExpr Predicate
Owen Taylor3473f882001-02-23 17:55:21 +000010373 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010374 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010375 * Square brackets are used to filter expressions in the same way that
10376 * they are used in location paths. It is an error if the expression to
10377 * be filtered does not evaluate to a node-set. The context node list
10378 * used for evaluating the expression in square brackets is the node-set
10379 * to be filtered listed in document order.
10380 */
10381
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010382static void
10383xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10384 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010385 CHECK_ERROR;
10386 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010387
Owen Taylor3473f882001-02-23 17:55:21 +000010388 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010389 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +000010390 SKIP_BLANKS;
10391 }
10392
Daniel Veillard45490ae2008-07-29 09:13:19 +000010393
Owen Taylor3473f882001-02-23 17:55:21 +000010394}
10395
10396/**
10397 * xmlXPathScanName:
10398 * @ctxt: the XPath Parser context
10399 *
10400 * Trickery: parse an XML name but without consuming the input flow
10401 * Needed to avoid insanity in the parser state.
10402 *
10403 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10404 * CombiningChar | Extender
10405 *
10406 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10407 *
10408 * [6] Names ::= Name (S Name)*
10409 *
10410 * Returns the Name parsed or NULL
10411 */
10412
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010413static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +000010414xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +000010415 int len = 0, l;
10416 int c;
Daniel Veillard03226812004-11-01 14:55:21 +000010417 const xmlChar *cur;
10418 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +000010419
Daniel Veillard03226812004-11-01 14:55:21 +000010420 cur = ctxt->cur;
10421
10422 c = CUR_CHAR(l);
10423 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10424 (!IS_LETTER(c) && (c != '_') &&
10425 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010426 return(NULL);
10427 }
10428
Daniel Veillard03226812004-11-01 14:55:21 +000010429 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10430 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10431 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000010432 (c == '_') || (c == ':') ||
Daniel Veillard03226812004-11-01 14:55:21 +000010433 (IS_COMBINING(c)) ||
10434 (IS_EXTENDER(c)))) {
10435 len += l;
10436 NEXTL(l);
10437 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +000010438 }
Daniel Veillard03226812004-11-01 14:55:21 +000010439 ret = xmlStrndup(cur, ctxt->cur - cur);
10440 ctxt->cur = cur;
10441 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +000010442}
10443
10444/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010445 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010446 * @ctxt: the XPath Parser context
10447 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010448 * [19] PathExpr ::= LocationPath
10449 * | FilterExpr
10450 * | FilterExpr '/' RelativeLocationPath
10451 * | FilterExpr '//' RelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000010452 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010453 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010454 * The / operator and // operators combine an arbitrary expression
10455 * and a relative location path. It is an error if the expression
10456 * does not evaluate to a node-set.
10457 * The / operator does composition in the same way as when / is
10458 * used in a location path. As in location paths, // is short for
10459 * /descendant-or-self::node()/.
10460 */
10461
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010462static void
10463xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010464 int lc = 1; /* Should we branch to LocationPath ? */
10465 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10466
10467 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010468 if ((CUR == '$') || (CUR == '(') ||
10469 (IS_ASCII_DIGIT(CUR)) ||
William M. Brackd1757ab2004-10-02 22:07:48 +000010470 (CUR == '\'') || (CUR == '"') ||
10471 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010472 lc = 0;
10473 } else if (CUR == '*') {
10474 /* relative or absolute location path */
10475 lc = 1;
10476 } else if (CUR == '/') {
10477 /* relative or absolute location path */
10478 lc = 1;
10479 } else if (CUR == '@') {
10480 /* relative abbreviated attribute location path */
10481 lc = 1;
10482 } else if (CUR == '.') {
10483 /* relative abbreviated attribute location path */
10484 lc = 1;
10485 } else {
10486 /*
10487 * Problem is finding if we have a name here whether it's:
10488 * - a nodetype
10489 * - a function call in which case it's followed by '('
10490 * - an axis in which case it's followed by ':'
10491 * - a element name
10492 * We do an a priori analysis here rather than having to
10493 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +000010494 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +000010495 * read/write/debug.
10496 */
10497 SKIP_BLANKS;
10498 name = xmlXPathScanName(ctxt);
10499 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10500#ifdef DEBUG_STEP
10501 xmlGenericError(xmlGenericErrorContext,
10502 "PathExpr: Axis\n");
10503#endif
10504 lc = 1;
10505 xmlFree(name);
10506 } else if (name != NULL) {
10507 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +000010508
Daniel Veillard45490ae2008-07-29 09:13:19 +000010509
Owen Taylor3473f882001-02-23 17:55:21 +000010510 while (NXT(len) != 0) {
10511 if (NXT(len) == '/') {
10512 /* element name */
10513#ifdef DEBUG_STEP
10514 xmlGenericError(xmlGenericErrorContext,
10515 "PathExpr: AbbrRelLocation\n");
10516#endif
10517 lc = 1;
10518 break;
William M. Brack76e95df2003-10-18 16:20:14 +000010519 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +000010520 /* ignore blanks */
10521 ;
Owen Taylor3473f882001-02-23 17:55:21 +000010522 } else if (NXT(len) == ':') {
10523#ifdef DEBUG_STEP
10524 xmlGenericError(xmlGenericErrorContext,
10525 "PathExpr: AbbrRelLocation\n");
10526#endif
10527 lc = 1;
10528 break;
10529 } else if ((NXT(len) == '(')) {
10530 /* Note Type or Function */
10531 if (xmlXPathIsNodeType(name)) {
10532#ifdef DEBUG_STEP
10533 xmlGenericError(xmlGenericErrorContext,
10534 "PathExpr: Type search\n");
10535#endif
10536 lc = 1;
10537 } else {
10538#ifdef DEBUG_STEP
10539 xmlGenericError(xmlGenericErrorContext,
10540 "PathExpr: function call\n");
10541#endif
10542 lc = 0;
10543 }
10544 break;
10545 } else if ((NXT(len) == '[')) {
10546 /* element name */
10547#ifdef DEBUG_STEP
10548 xmlGenericError(xmlGenericErrorContext,
10549 "PathExpr: AbbrRelLocation\n");
10550#endif
10551 lc = 1;
10552 break;
10553 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10554 (NXT(len) == '=')) {
10555 lc = 1;
10556 break;
10557 } else {
10558 lc = 1;
10559 break;
10560 }
10561 len++;
10562 }
10563 if (NXT(len) == 0) {
10564#ifdef DEBUG_STEP
10565 xmlGenericError(xmlGenericErrorContext,
10566 "PathExpr: AbbrRelLocation\n");
10567#endif
10568 /* element name */
10569 lc = 1;
10570 }
10571 xmlFree(name);
10572 } else {
William M. Brack08171912003-12-29 02:52:11 +000010573 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +000010574 XP_ERROR(XPATH_EXPR_ERROR);
10575 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000010576 }
Owen Taylor3473f882001-02-23 17:55:21 +000010577
10578 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010579 if (CUR == '/') {
10580 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10581 } else {
10582 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010583 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010584 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010585 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010586 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010587 CHECK_ERROR;
10588 if ((CUR == '/') && (NXT(1) == '/')) {
10589 SKIP(2);
10590 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010591
10592 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10593 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10594 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10595
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010596 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010597 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010598 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010599 }
10600 }
10601 SKIP_BLANKS;
10602}
10603
10604/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010605 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010606 * @ctxt: the XPath Parser context
10607 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010608 * [18] UnionExpr ::= PathExpr
10609 * | UnionExpr '|' PathExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010610 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010611 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010612 */
10613
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010614static void
10615xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10616 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010617 CHECK_ERROR;
10618 SKIP_BLANKS;
10619 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010620 int op1 = ctxt->comp->last;
10621 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010622
10623 NEXT;
10624 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010625 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010626
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010627 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10628
Owen Taylor3473f882001-02-23 17:55:21 +000010629 SKIP_BLANKS;
10630 }
Owen Taylor3473f882001-02-23 17:55:21 +000010631}
10632
10633/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010634 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010635 * @ctxt: the XPath Parser context
10636 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010637 * [27] UnaryExpr ::= UnionExpr
10638 * | '-' UnaryExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010639 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010640 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010641 */
10642
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010643static void
10644xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010645 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010646 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010647
10648 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +000010649 while (CUR == '-') {
10650 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010651 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010652 NEXT;
10653 SKIP_BLANKS;
10654 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010655
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010656 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010657 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010658 if (found) {
10659 if (minus)
10660 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10661 else
10662 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010663 }
10664}
10665
10666/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010667 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010668 * @ctxt: the XPath Parser context
10669 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010670 * [26] MultiplicativeExpr ::= UnaryExpr
10671 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10672 * | MultiplicativeExpr 'div' UnaryExpr
10673 * | MultiplicativeExpr 'mod' UnaryExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010674 * [34] MultiplyOperator ::= '*'
10675 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010676 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010677 */
10678
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010679static void
10680xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10681 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010682 CHECK_ERROR;
10683 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010684 while ((CUR == '*') ||
Owen Taylor3473f882001-02-23 17:55:21 +000010685 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10686 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10687 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010688 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010689
10690 if (CUR == '*') {
10691 op = 0;
10692 NEXT;
10693 } else if (CUR == 'd') {
10694 op = 1;
10695 SKIP(3);
10696 } else if (CUR == 'm') {
10697 op = 2;
10698 SKIP(3);
10699 }
10700 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010701 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010702 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010703 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010704 SKIP_BLANKS;
10705 }
10706}
10707
10708/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010709 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010710 * @ctxt: the XPath Parser context
10711 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010712 * [25] AdditiveExpr ::= MultiplicativeExpr
10713 * | AdditiveExpr '+' MultiplicativeExpr
10714 * | AdditiveExpr '-' MultiplicativeExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010715 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010716 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010717 */
10718
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010719static void
10720xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010721
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010722 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010723 CHECK_ERROR;
10724 SKIP_BLANKS;
10725 while ((CUR == '+') || (CUR == '-')) {
10726 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010727 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010728
10729 if (CUR == '+') plus = 1;
10730 else plus = 0;
10731 NEXT;
10732 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010733 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010734 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010735 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010736 SKIP_BLANKS;
10737 }
10738}
10739
10740/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010741 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010742 * @ctxt: the XPath Parser context
10743 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010744 * [24] RelationalExpr ::= AdditiveExpr
10745 * | RelationalExpr '<' AdditiveExpr
10746 * | RelationalExpr '>' AdditiveExpr
10747 * | RelationalExpr '<=' AdditiveExpr
10748 * | RelationalExpr '>=' AdditiveExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010749 *
10750 * A <= B > C is allowed ? Answer from James, yes with
10751 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10752 * which is basically what got implemented.
10753 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010754 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +000010755 * on the stack
10756 */
10757
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010758static void
10759xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10760 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010761 CHECK_ERROR;
10762 SKIP_BLANKS;
10763 while ((CUR == '<') ||
10764 (CUR == '>') ||
10765 ((CUR == '<') && (NXT(1) == '=')) ||
10766 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010767 int inf, strict;
10768 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010769
10770 if (CUR == '<') inf = 1;
10771 else inf = 0;
10772 if (NXT(1) == '=') strict = 0;
10773 else strict = 1;
10774 NEXT;
10775 if (!strict) NEXT;
10776 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010777 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010778 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010779 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +000010780 SKIP_BLANKS;
10781 }
10782}
10783
10784/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010785 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010786 * @ctxt: the XPath Parser context
10787 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010788 * [23] EqualityExpr ::= RelationalExpr
10789 * | EqualityExpr '=' RelationalExpr
10790 * | EqualityExpr '!=' RelationalExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010791 *
10792 * A != B != C is allowed ? Answer from James, yes with
10793 * (RelationalExpr = RelationalExpr) = RelationalExpr
10794 * (RelationalExpr != RelationalExpr) != RelationalExpr
10795 * which is basically what got implemented.
10796 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010797 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010798 *
10799 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010800static void
10801xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10802 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010803 CHECK_ERROR;
10804 SKIP_BLANKS;
10805 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010806 int eq;
10807 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010808
10809 if (CUR == '=') eq = 1;
10810 else eq = 0;
10811 NEXT;
10812 if (!eq) NEXT;
10813 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010814 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010815 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010816 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010817 SKIP_BLANKS;
10818 }
10819}
10820
10821/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010822 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010823 * @ctxt: the XPath Parser context
10824 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010825 * [22] AndExpr ::= EqualityExpr
10826 * | AndExpr 'and' EqualityExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010827 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010828 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010829 *
10830 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010831static void
10832xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10833 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010834 CHECK_ERROR;
10835 SKIP_BLANKS;
10836 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010837 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010838 SKIP(3);
10839 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010840 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010841 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010842 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010843 SKIP_BLANKS;
10844 }
10845}
10846
10847/**
Daniel Veillard591b4be2003-02-09 23:33:36 +000010848 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010849 * @ctxt: the XPath Parser context
10850 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010851 * [14] Expr ::= OrExpr
10852 * [21] OrExpr ::= AndExpr
10853 * | OrExpr 'or' AndExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010854 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010855 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +000010856 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010857static void
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010858xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010859 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010860 CHECK_ERROR;
10861 SKIP_BLANKS;
10862 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010863 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010864 SKIP(2);
10865 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010866 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010867 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010868 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10869 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +000010870 SKIP_BLANKS;
10871 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010872 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010873 /* more ops could be optimized too */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010874 /*
10875 * This is the main place to eliminate sorting for
10876 * operations which don't require a sorted node-set.
10877 * E.g. count().
10878 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010879 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10880 }
Owen Taylor3473f882001-02-23 17:55:21 +000010881}
10882
10883/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010884 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +000010885 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010886 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +000010887 *
10888 * [8] Predicate ::= '[' PredicateExpr ']'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010889 * [9] PredicateExpr ::= Expr
Owen Taylor3473f882001-02-23 17:55:21 +000010890 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010891 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +000010892 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010893static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010894xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010895 int op1 = ctxt->comp->last;
10896
10897 SKIP_BLANKS;
10898 if (CUR != '[') {
10899 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10900 }
10901 NEXT;
10902 SKIP_BLANKS;
10903
10904 ctxt->comp->last = -1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000010905 /*
10906 * This call to xmlXPathCompileExpr() will deactivate sorting
10907 * of the predicate result.
10908 * TODO: Sorting is still activated for filters, since I'm not
10909 * sure if needed. Normally sorting should not be needed, since
10910 * a filter can only diminish the number of items in a sequence,
10911 * but won't change its order; so if the initial sequence is sorted,
10912 * subsequent sorting is not needed.
10913 */
10914 if (! filter)
10915 xmlXPathCompileExpr(ctxt, 0);
10916 else
10917 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010918 CHECK_ERROR;
10919
10920 if (CUR != ']') {
10921 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10922 }
10923
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010924 if (filter)
10925 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10926 else
10927 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010928
10929 NEXT;
10930 SKIP_BLANKS;
10931}
10932
10933/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010934 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +000010935 * @ctxt: the XPath Parser context
10936 * @test: pointer to a xmlXPathTestVal
10937 * @type: pointer to a xmlXPathTypeVal
10938 * @prefix: placeholder for a possible name prefix
10939 *
10940 * [7] NodeTest ::= NameTest
10941 * | NodeType '(' ')'
10942 * | 'processing-instruction' '(' Literal ')'
10943 *
10944 * [37] NameTest ::= '*'
10945 * | NCName ':' '*'
10946 * | QName
10947 * [38] NodeType ::= 'comment'
10948 * | 'text'
10949 * | 'processing-instruction'
10950 * | 'node'
10951 *
William M. Brack08171912003-12-29 02:52:11 +000010952 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +000010953 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010954static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010955xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10956 xmlXPathTypeVal *type, const xmlChar **prefix,
10957 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +000010958 int blanks;
10959
10960 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10961 STRANGE;
10962 return(NULL);
10963 }
William M. Brack78637da2003-07-31 14:47:38 +000010964 *type = (xmlXPathTypeVal) 0;
10965 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010966 *prefix = NULL;
10967 SKIP_BLANKS;
10968
10969 if ((name == NULL) && (CUR == '*')) {
10970 /*
10971 * All elements
10972 */
10973 NEXT;
10974 *test = NODE_TEST_ALL;
10975 return(NULL);
10976 }
10977
10978 if (name == NULL)
10979 name = xmlXPathParseNCName(ctxt);
10980 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010981 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010982 }
10983
William M. Brack76e95df2003-10-18 16:20:14 +000010984 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +000010985 SKIP_BLANKS;
10986 if (CUR == '(') {
10987 NEXT;
10988 /*
10989 * NodeType or PI search
10990 */
10991 if (xmlStrEqual(name, BAD_CAST "comment"))
10992 *type = NODE_TYPE_COMMENT;
10993 else if (xmlStrEqual(name, BAD_CAST "node"))
10994 *type = NODE_TYPE_NODE;
10995 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10996 *type = NODE_TYPE_PI;
10997 else if (xmlStrEqual(name, BAD_CAST "text"))
10998 *type = NODE_TYPE_TEXT;
10999 else {
11000 if (name != NULL)
11001 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000011002 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011003 }
11004
11005 *test = NODE_TEST_TYPE;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011006
Owen Taylor3473f882001-02-23 17:55:21 +000011007 SKIP_BLANKS;
11008 if (*type == NODE_TYPE_PI) {
11009 /*
11010 * Specific case: search a PI by name.
11011 */
Owen Taylor3473f882001-02-23 17:55:21 +000011012 if (name != NULL)
11013 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +000011014 name = NULL;
11015 if (CUR != ')') {
11016 name = xmlXPathParseLiteral(ctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000011017 CHECK_ERROR NULL;
Daniel Veillarded23b7d2002-05-27 12:16:02 +000011018 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +000011019 SKIP_BLANKS;
11020 }
Owen Taylor3473f882001-02-23 17:55:21 +000011021 }
11022 if (CUR != ')') {
11023 if (name != NULL)
11024 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000011025 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011026 }
11027 NEXT;
11028 return(name);
11029 }
11030 *test = NODE_TEST_NAME;
11031 if ((!blanks) && (CUR == ':')) {
11032 NEXT;
11033
11034 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011035 * Since currently the parser context don't have a
11036 * namespace list associated:
11037 * The namespace name for this prefix can be computed
11038 * only at evaluation time. The compilation is done
11039 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +000011040 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011041#if 0
Owen Taylor3473f882001-02-23 17:55:21 +000011042 *prefix = xmlXPathNsLookup(ctxt->context, name);
11043 if (name != NULL)
11044 xmlFree(name);
11045 if (*prefix == NULL) {
11046 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11047 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011048#else
11049 *prefix = name;
11050#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011051
11052 if (CUR == '*') {
11053 /*
11054 * All elements
11055 */
11056 NEXT;
11057 *test = NODE_TEST_ALL;
11058 return(NULL);
11059 }
11060
11061 name = xmlXPathParseNCName(ctxt);
11062 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011063 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011064 }
11065 }
11066 return(name);
11067}
11068
11069/**
11070 * xmlXPathIsAxisName:
11071 * @name: a preparsed name token
11072 *
11073 * [6] AxisName ::= 'ancestor'
11074 * | 'ancestor-or-self'
11075 * | 'attribute'
11076 * | 'child'
11077 * | 'descendant'
11078 * | 'descendant-or-self'
11079 * | 'following'
11080 * | 'following-sibling'
11081 * | 'namespace'
11082 * | 'parent'
11083 * | 'preceding'
11084 * | 'preceding-sibling'
11085 * | 'self'
11086 *
11087 * Returns the axis or 0
11088 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011089static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +000011090xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +000011091 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011092 switch (name[0]) {
11093 case 'a':
11094 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11095 ret = AXIS_ANCESTOR;
11096 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11097 ret = AXIS_ANCESTOR_OR_SELF;
11098 if (xmlStrEqual(name, BAD_CAST "attribute"))
11099 ret = AXIS_ATTRIBUTE;
11100 break;
11101 case 'c':
11102 if (xmlStrEqual(name, BAD_CAST "child"))
11103 ret = AXIS_CHILD;
11104 break;
11105 case 'd':
11106 if (xmlStrEqual(name, BAD_CAST "descendant"))
11107 ret = AXIS_DESCENDANT;
11108 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11109 ret = AXIS_DESCENDANT_OR_SELF;
11110 break;
11111 case 'f':
11112 if (xmlStrEqual(name, BAD_CAST "following"))
11113 ret = AXIS_FOLLOWING;
11114 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11115 ret = AXIS_FOLLOWING_SIBLING;
11116 break;
11117 case 'n':
11118 if (xmlStrEqual(name, BAD_CAST "namespace"))
11119 ret = AXIS_NAMESPACE;
11120 break;
11121 case 'p':
11122 if (xmlStrEqual(name, BAD_CAST "parent"))
11123 ret = AXIS_PARENT;
11124 if (xmlStrEqual(name, BAD_CAST "preceding"))
11125 ret = AXIS_PRECEDING;
11126 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11127 ret = AXIS_PRECEDING_SIBLING;
11128 break;
11129 case 's':
11130 if (xmlStrEqual(name, BAD_CAST "self"))
11131 ret = AXIS_SELF;
11132 break;
11133 }
11134 return(ret);
11135}
11136
11137/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011138 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +000011139 * @ctxt: the XPath Parser context
11140 *
11141 * [4] Step ::= AxisSpecifier NodeTest Predicate*
Daniel Veillard45490ae2008-07-29 09:13:19 +000011142 * | AbbreviatedStep
Owen Taylor3473f882001-02-23 17:55:21 +000011143 *
11144 * [12] AbbreviatedStep ::= '.' | '..'
11145 *
11146 * [5] AxisSpecifier ::= AxisName '::'
11147 * | AbbreviatedAxisSpecifier
11148 *
11149 * [13] AbbreviatedAxisSpecifier ::= '@'?
11150 *
11151 * Modified for XPtr range support as:
11152 *
11153 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11154 * | AbbreviatedStep
11155 * | 'range-to' '(' Expr ')' Predicate*
11156 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011157 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +000011158 * A location step of . is short for self::node(). This is
11159 * particularly useful in conjunction with //. For example, the
11160 * location path .//para is short for
11161 * self::node()/descendant-or-self::node()/child::para
11162 * and so will select all para descendant elements of the context
11163 * node.
11164 * Similarly, a location step of .. is short for parent::node().
11165 * For example, ../title is short for parent::node()/child::title
11166 * and so will select the title children of the parent of the context
11167 * node.
11168 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011169static void
11170xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011171#ifdef LIBXML_XPTR_ENABLED
11172 int rangeto = 0;
11173 int op2 = -1;
11174#endif
11175
Owen Taylor3473f882001-02-23 17:55:21 +000011176 SKIP_BLANKS;
11177 if ((CUR == '.') && (NXT(1) == '.')) {
11178 SKIP(2);
11179 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011180 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11181 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011182 } else if (CUR == '.') {
11183 NEXT;
11184 SKIP_BLANKS;
11185 } else {
11186 xmlChar *name = NULL;
11187 const xmlChar *prefix = NULL;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011188 xmlXPathTestVal test = (xmlXPathTestVal) 0;
William M. Brack78637da2003-07-31 14:47:38 +000011189 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011190 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011191 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +000011192
11193 /*
11194 * The modification needed for XPointer change to the production
11195 */
11196#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011197 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +000011198 name = xmlXPathParseNCName(ctxt);
11199 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011200 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011201 xmlFree(name);
11202 SKIP_BLANKS;
11203 if (CUR != '(') {
11204 XP_ERROR(XPATH_EXPR_ERROR);
11205 }
11206 NEXT;
11207 SKIP_BLANKS;
11208
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011209 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011210 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +000011211 CHECK_ERROR;
11212
11213 SKIP_BLANKS;
11214 if (CUR != ')') {
11215 XP_ERROR(XPATH_EXPR_ERROR);
11216 }
11217 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011218 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000011219 goto eval_predicates;
11220 }
11221 }
11222#endif
Daniel Veillard2156a562001-04-28 12:24:34 +000011223 if (CUR == '*') {
11224 axis = AXIS_CHILD;
11225 } else {
11226 if (name == NULL)
11227 name = xmlXPathParseNCName(ctxt);
11228 if (name != NULL) {
11229 axis = xmlXPathIsAxisName(name);
11230 if (axis != 0) {
11231 SKIP_BLANKS;
11232 if ((CUR == ':') && (NXT(1) == ':')) {
11233 SKIP(2);
11234 xmlFree(name);
11235 name = NULL;
11236 } else {
11237 /* an element name can conflict with an axis one :-\ */
11238 axis = AXIS_CHILD;
11239 }
Owen Taylor3473f882001-02-23 17:55:21 +000011240 } else {
Owen Taylor3473f882001-02-23 17:55:21 +000011241 axis = AXIS_CHILD;
11242 }
Daniel Veillard2156a562001-04-28 12:24:34 +000011243 } else if (CUR == '@') {
11244 NEXT;
11245 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +000011246 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +000011247 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +000011248 }
Owen Taylor3473f882001-02-23 17:55:21 +000011249 }
11250
11251 CHECK_ERROR;
11252
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011253 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +000011254 if (test == 0)
11255 return;
11256
Daniel Veillarded6c5492005-07-23 15:00:22 +000011257 if ((prefix != NULL) && (ctxt->context != NULL) &&
11258 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11259 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11260 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11261 }
11262 }
Owen Taylor3473f882001-02-23 17:55:21 +000011263#ifdef DEBUG_STEP
11264 xmlGenericError(xmlGenericErrorContext,
11265 "Basis : computing new set\n");
11266#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011267
Owen Taylor3473f882001-02-23 17:55:21 +000011268#ifdef DEBUG_STEP
11269 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011270 if (ctxt->value == NULL)
11271 xmlGenericError(xmlGenericErrorContext, "no value\n");
11272 else if (ctxt->value->nodesetval == NULL)
11273 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11274 else
11275 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011276#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011277
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011278#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +000011279eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011280#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011281 op1 = ctxt->comp->last;
11282 ctxt->comp->last = -1;
11283
Owen Taylor3473f882001-02-23 17:55:21 +000011284 SKIP_BLANKS;
11285 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011286 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011287 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011288
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011289#ifdef LIBXML_XPTR_ENABLED
11290 if (rangeto) {
11291 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11292 } else
11293#endif
11294 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11295 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011296
Owen Taylor3473f882001-02-23 17:55:21 +000011297 }
11298#ifdef DEBUG_STEP
11299 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011300 if (ctxt->value == NULL)
11301 xmlGenericError(xmlGenericErrorContext, "no value\n");
11302 else if (ctxt->value->nodesetval == NULL)
11303 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11304 else
11305 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11306 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011307#endif
11308}
11309
11310/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011311 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011312 * @ctxt: the XPath Parser context
11313 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011314 * [3] RelativeLocationPath ::= Step
11315 * | RelativeLocationPath '/' Step
11316 * | AbbreviatedRelativeLocationPath
11317 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
Owen Taylor3473f882001-02-23 17:55:21 +000011318 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011319 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +000011320 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011321static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011322xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011323(xmlXPathParserContextPtr ctxt) {
11324 SKIP_BLANKS;
11325 if ((CUR == '/') && (NXT(1) == '/')) {
11326 SKIP(2);
11327 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011328 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11329 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011330 } else if (CUR == '/') {
11331 NEXT;
11332 SKIP_BLANKS;
11333 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011334 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011335 SKIP_BLANKS;
11336 while (CUR == '/') {
11337 if ((CUR == '/') && (NXT(1) == '/')) {
11338 SKIP(2);
11339 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011340 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +000011341 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011342 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011343 } else if (CUR == '/') {
11344 NEXT;
11345 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011346 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011347 }
11348 SKIP_BLANKS;
11349 }
11350}
11351
11352/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011353 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011354 * @ctxt: the XPath Parser context
11355 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011356 * [1] LocationPath ::= RelativeLocationPath
11357 * | AbsoluteLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011358 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
Daniel Veillard45490ae2008-07-29 09:13:19 +000011359 * | AbbreviatedAbsoluteLocationPath
11360 * [10] AbbreviatedAbsoluteLocationPath ::=
11361 * '//' RelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011362 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011363 * Compile a location path
11364 *
Owen Taylor3473f882001-02-23 17:55:21 +000011365 * // is short for /descendant-or-self::node()/. For example,
11366 * //para is short for /descendant-or-self::node()/child::para and
11367 * so will select any para element in the document (even a para element
11368 * that is a document element will be selected by //para since the
11369 * document element node is a child of the root node); div//para is
11370 * short for div/descendant-or-self::node()/child::para and so will
11371 * select all para descendants of div children.
11372 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011373static void
11374xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000011375 SKIP_BLANKS;
11376 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011377 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011378 } else {
11379 while (CUR == '/') {
11380 if ((CUR == '/') && (NXT(1) == '/')) {
11381 SKIP(2);
11382 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011383 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11384 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011385 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011386 } else if (CUR == '/') {
11387 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +000011388 SKIP_BLANKS;
11389 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +000011390 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +000011391 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011392 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011393 }
11394 }
11395 }
11396}
11397
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011398/************************************************************************
11399 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011400 * XPath precompiled expression evaluation *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011401 * *
11402 ************************************************************************/
11403
Daniel Veillardf06307e2001-07-03 10:35:50 +000011404static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011405xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11406
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011407#ifdef DEBUG_STEP
11408static void
Daniel Veillard074f37e2008-09-01 13:38:22 +000011409xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011410 int nbNodes)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011411{
Daniel Veillardf06307e2001-07-03 10:35:50 +000011412 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillard074f37e2008-09-01 13:38:22 +000011413 switch (op->value) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011414 case AXIS_ANCESTOR:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011415 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011416 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011417 case AXIS_ANCESTOR_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011418 xmlGenericError(xmlGenericErrorContext,
11419 "axis 'ancestors-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011420 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011421 case AXIS_ATTRIBUTE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011422 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011423 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011424 case AXIS_CHILD:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011425 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011426 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011427 case AXIS_DESCENDANT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011428 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011429 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011430 case AXIS_DESCENDANT_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011431 xmlGenericError(xmlGenericErrorContext,
11432 "axis 'descendant-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011433 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011434 case AXIS_FOLLOWING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011435 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011436 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011437 case AXIS_FOLLOWING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011438 xmlGenericError(xmlGenericErrorContext,
11439 "axis 'following-siblings' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011440 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011441 case AXIS_NAMESPACE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011442 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011443 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011444 case AXIS_PARENT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011445 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011446 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011447 case AXIS_PRECEDING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011448 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011449 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011450 case AXIS_PRECEDING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011451 xmlGenericError(xmlGenericErrorContext,
11452 "axis 'preceding-sibling' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011453 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011454 case AXIS_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011455 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011456 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011457 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011458 xmlGenericError(xmlGenericErrorContext,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011459 " context contains %d nodes\n", nbNodes);
Daniel Veillard074f37e2008-09-01 13:38:22 +000011460 switch (op->value2) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011461 case NODE_TEST_NONE:
11462 xmlGenericError(xmlGenericErrorContext,
11463 " searching for none !!!\n");
11464 break;
11465 case NODE_TEST_TYPE:
11466 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011467 " searching for type %d\n", op->value3);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011468 break;
11469 case NODE_TEST_PI:
11470 xmlGenericError(xmlGenericErrorContext,
11471 " searching for PI !!!\n");
11472 break;
11473 case NODE_TEST_ALL:
11474 xmlGenericError(xmlGenericErrorContext,
11475 " searching for *\n");
11476 break;
11477 case NODE_TEST_NS:
11478 xmlGenericError(xmlGenericErrorContext,
11479 " searching for namespace %s\n",
Daniel Veillard074f37e2008-09-01 13:38:22 +000011480 op->value5);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011481 break;
11482 case NODE_TEST_NAME:
11483 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011484 " searching for name %s\n", op->value5);
11485 if (op->value4)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011486 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011487 " with namespace %s\n", op->value4);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011488 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011489 }
11490 xmlGenericError(xmlGenericErrorContext, "Testing : ");
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011491}
11492#endif /* DEBUG_STEP */
11493
11494static int
11495xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11496 xmlXPathStepOpPtr op,
11497 xmlNodeSetPtr set,
11498 int contextSize,
11499 int hasNsNodes)
11500{
11501 if (op->ch1 != -1) {
11502 xmlXPathCompExprPtr comp = ctxt->comp;
11503 /*
11504 * Process inner predicates first.
11505 */
11506 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11507 /*
11508 * TODO: raise an internal error.
11509 */
11510 }
11511 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11512 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11513 CHECK_ERROR0;
11514 if (contextSize <= 0)
11515 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011516 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011517 if (op->ch2 != -1) {
11518 xmlXPathContextPtr xpctxt = ctxt->context;
11519 xmlNodePtr contextNode, oldContextNode;
11520 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011521 int i, res, contextPos = 0, newContextSize;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011522 xmlXPathStepOpPtr exprOp;
11523 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11524
11525#ifdef LIBXML_XPTR_ENABLED
11526 /*
11527 * URGENT TODO: Check the following:
11528 * We don't expect location sets if evaluating prediates, right?
11529 * Only filters should expect location sets, right?
11530 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011531#endif
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011532 /*
11533 * SPEC XPath 1.0:
11534 * "For each node in the node-set to be filtered, the
11535 * PredicateExpr is evaluated with that node as the
11536 * context node, with the number of nodes in the
11537 * node-set as the context size, and with the proximity
11538 * position of the node in the node-set with respect to
11539 * the axis as the context position;"
11540 * @oldset is the node-set" to be filtered.
11541 *
11542 * SPEC XPath 1.0:
11543 * "only predicates change the context position and
11544 * context size (see [2.4 Predicates])."
11545 * Example:
11546 * node-set context pos
11547 * nA 1
11548 * nB 2
11549 * nC 3
11550 * After applying predicate [position() > 1] :
11551 * node-set context pos
11552 * nB 1
11553 * nC 2
11554 */
11555 oldContextNode = xpctxt->node;
11556 oldContextDoc = xpctxt->doc;
11557 /*
11558 * Get the expression of this predicate.
11559 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000011560 exprOp = &ctxt->comp->steps[op->ch2];
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011561 newContextSize = 0;
11562 for (i = 0; i < set->nodeNr; i++) {
11563 if (set->nodeTab[i] == NULL)
11564 continue;
11565
11566 contextNode = set->nodeTab[i];
11567 xpctxt->node = contextNode;
11568 xpctxt->contextSize = contextSize;
11569 xpctxt->proximityPosition = ++contextPos;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011570
11571 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011572 * Also set the xpath document in case things like
11573 * key() are evaluated in the predicate.
11574 */
11575 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11576 (contextNode->doc != NULL))
11577 xpctxt->doc = contextNode->doc;
11578 /*
11579 * Evaluate the predicate expression with 1 context node
11580 * at a time; this node is packaged into a node set; this
11581 * node set is handed over to the evaluation mechanism.
11582 */
11583 if (contextObj == NULL)
11584 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11585 else
11586 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11587 contextNode);
11588
11589 valuePush(ctxt, contextObj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011590
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011591 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011592
William M. Brack0bcec062007-02-14 02:15:19 +000011593 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11594 xmlXPathNodeSetClear(set, hasNsNodes);
11595 newContextSize = 0;
11596 goto evaluation_exit;
11597 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011598
11599 if (res != 0) {
11600 newContextSize++;
11601 } else {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011602 /*
11603 * Remove the entry from the initial node set.
11604 */
11605 set->nodeTab[i] = NULL;
11606 if (contextNode->type == XML_NAMESPACE_DECL)
11607 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011608 }
11609 if (ctxt->value == contextObj) {
11610 /*
11611 * Don't free the temporary XPath object holding the
11612 * context node, in order to avoid massive recreation
11613 * inside this loop.
11614 */
11615 valuePop(ctxt);
11616 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11617 } else {
11618 /*
11619 * TODO: The object was lost in the evaluation machinery.
11620 * Can this happen? Maybe in internal-error cases.
11621 */
11622 contextObj = NULL;
11623 }
11624 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011625
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011626 if (contextObj != NULL) {
11627 if (ctxt->value == contextObj)
11628 valuePop(ctxt);
11629 xmlXPathReleaseObject(xpctxt, contextObj);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011630 }
William M. Brack0bcec062007-02-14 02:15:19 +000011631evaluation_exit:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011632 if (exprRes != NULL)
11633 xmlXPathReleaseObject(ctxt->context, exprRes);
11634 /*
11635 * Reset/invalidate the context.
11636 */
11637 xpctxt->node = oldContextNode;
11638 xpctxt->doc = oldContextDoc;
11639 xpctxt->contextSize = -1;
11640 xpctxt->proximityPosition = -1;
11641 return(newContextSize);
11642 }
11643 return(contextSize);
11644}
11645
11646static int
11647xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11648 xmlXPathStepOpPtr op,
11649 xmlNodeSetPtr set,
11650 int contextSize,
11651 int minPos,
11652 int maxPos,
11653 int hasNsNodes)
11654{
11655 if (op->ch1 != -1) {
11656 xmlXPathCompExprPtr comp = ctxt->comp;
11657 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11658 /*
11659 * TODO: raise an internal error.
11660 */
11661 }
11662 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11663 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11664 CHECK_ERROR0;
11665 if (contextSize <= 0)
11666 return(0);
11667 }
11668 /*
11669 * Check if the node set contains a sufficient number of nodes for
11670 * the requested range.
11671 */
11672 if (contextSize < minPos) {
11673 xmlXPathNodeSetClear(set, hasNsNodes);
11674 return(0);
11675 }
11676 if (op->ch2 == -1) {
11677 /*
11678 * TODO: Can this ever happen?
11679 */
11680 return (contextSize);
11681 } else {
11682 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011683 int i, pos = 0, newContextSize = 0, contextPos = 0, res;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011684 xmlXPathStepOpPtr exprOp;
11685 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11686 xmlNodePtr oldContextNode, contextNode = NULL;
11687 xmlXPathContextPtr xpctxt = ctxt->context;
11688
11689#ifdef LIBXML_XPTR_ENABLED
11690 /*
11691 * URGENT TODO: Check the following:
11692 * We don't expect location sets if evaluating prediates, right?
11693 * Only filters should expect location sets, right?
11694 */
11695#endif /* LIBXML_XPTR_ENABLED */
11696
11697 /*
11698 * Save old context.
11699 */
11700 oldContextNode = xpctxt->node;
11701 oldContextDoc = xpctxt->doc;
11702 /*
11703 * Get the expression of this predicate.
11704 */
11705 exprOp = &ctxt->comp->steps[op->ch2];
11706 for (i = 0; i < set->nodeNr; i++) {
11707 if (set->nodeTab[i] == NULL)
11708 continue;
11709
11710 contextNode = set->nodeTab[i];
11711 xpctxt->node = contextNode;
11712 xpctxt->contextSize = contextSize;
11713 xpctxt->proximityPosition = ++contextPos;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011714
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011715 /*
11716 * Initialize the new set.
11717 * Also set the xpath document in case things like
11718 * key() evaluation are attempted on the predicate
11719 */
11720 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11721 (contextNode->doc != NULL))
11722 xpctxt->doc = contextNode->doc;
11723 /*
11724 * Evaluate the predicate expression with 1 context node
11725 * at a time; this node is packaged into a node set; this
11726 * node set is handed over to the evaluation mechanism.
11727 */
11728 if (contextObj == NULL)
11729 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11730 else
11731 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11732 contextNode);
11733
11734 valuePush(ctxt, contextObj);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011735 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011736
William M. Brackf1794562007-08-23 12:58:13 +000011737 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11738 xmlXPathObjectPtr tmp;
11739 /* pop the result */
11740 tmp = valuePop(ctxt);
11741 xmlXPathReleaseObject(xpctxt, tmp);
11742 /* then pop off contextObj, which will be freed later */
11743 valuePop(ctxt);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011744 goto evaluation_error;
William M. Brackf1794562007-08-23 12:58:13 +000011745 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011746
11747 if (res)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011748 pos++;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011749
11750 if (res && (pos >= minPos) && (pos <= maxPos)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011751 /*
11752 * Fits in the requested range.
11753 */
11754 newContextSize++;
11755 if (minPos == maxPos) {
11756 /*
11757 * Only 1 node was requested.
11758 */
11759 if (contextNode->type == XML_NAMESPACE_DECL) {
11760 /*
11761 * As always: take care of those nasty
11762 * namespace nodes.
11763 */
11764 set->nodeTab[i] = NULL;
11765 }
11766 xmlXPathNodeSetClear(set, hasNsNodes);
11767 set->nodeNr = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011768 set->nodeTab[0] = contextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011769 goto evaluation_exit;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011770 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011771 if (pos == maxPos) {
11772 /*
11773 * We are done.
11774 */
11775 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11776 goto evaluation_exit;
11777 }
11778 } else {
11779 /*
11780 * Remove the entry from the initial node set.
11781 */
11782 set->nodeTab[i] = NULL;
11783 if (contextNode->type == XML_NAMESPACE_DECL)
11784 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11785 }
11786 if (exprRes != NULL) {
11787 xmlXPathReleaseObject(ctxt->context, exprRes);
11788 exprRes = NULL;
11789 }
11790 if (ctxt->value == contextObj) {
11791 /*
11792 * Don't free the temporary XPath object holding the
11793 * context node, in order to avoid massive recreation
11794 * inside this loop.
11795 */
11796 valuePop(ctxt);
11797 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11798 } else {
11799 /*
11800 * The object was lost in the evaluation machinery.
11801 * Can this happen? Maybe in case of internal-errors.
11802 */
11803 contextObj = NULL;
11804 }
11805 }
11806 goto evaluation_exit;
11807
11808evaluation_error:
11809 xmlXPathNodeSetClear(set, hasNsNodes);
11810 newContextSize = 0;
11811
11812evaluation_exit:
11813 if (contextObj != NULL) {
11814 if (ctxt->value == contextObj)
11815 valuePop(ctxt);
11816 xmlXPathReleaseObject(xpctxt, contextObj);
11817 }
11818 if (exprRes != NULL)
11819 xmlXPathReleaseObject(ctxt->context, exprRes);
11820 /*
11821 * Reset/invalidate the context.
11822 */
11823 xpctxt->node = oldContextNode;
11824 xpctxt->doc = oldContextDoc;
11825 xpctxt->contextSize = -1;
11826 xpctxt->proximityPosition = -1;
11827 return(newContextSize);
11828 }
11829 return(contextSize);
11830}
11831
11832static int
11833xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
Daniel Veillard45490ae2008-07-29 09:13:19 +000011834 xmlXPathStepOpPtr op,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011835 int *maxPos)
11836{
11837
11838 xmlXPathStepOpPtr exprOp;
11839
11840 /*
11841 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11842 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000011843
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011844 /*
11845 * If not -1, then ch1 will point to:
11846 * 1) For predicates (XPATH_OP_PREDICATE):
11847 * - an inner predicate operator
11848 * 2) For filters (XPATH_OP_FILTER):
11849 * - an inner filter operater OR
11850 * - an expression selecting the node set.
11851 * E.g. "key('a', 'b')" or "(//foo | //bar)".
Daniel Veillard45490ae2008-07-29 09:13:19 +000011852 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011853 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11854 return(0);
11855
11856 if (op->ch2 != -1) {
11857 exprOp = &ctxt->comp->steps[op->ch2];
Daniel Veillard45490ae2008-07-29 09:13:19 +000011858 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011859 return(0);
11860
11861 if ((exprOp != NULL) &&
11862 (exprOp->op == XPATH_OP_VALUE) &&
11863 (exprOp->value4 != NULL) &&
11864 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11865 {
11866 /*
11867 * We have a "[n]" predicate here.
11868 * TODO: Unfortunately this simplistic test here is not
11869 * able to detect a position() predicate in compound
11870 * expressions like "[@attr = 'a" and position() = 1],
11871 * and even not the usage of position() in
11872 * "[position() = 1]"; thus - obviously - a position-range,
11873 * like it "[position() < 5]", is also not detected.
11874 * Maybe we could rewrite the AST to ease the optimization.
11875 */
11876 *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011877
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011878 if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
11879 (float) *maxPos)
Daniel Veillard45490ae2008-07-29 09:13:19 +000011880 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011881 return(1);
11882 }
11883 }
11884 return(0);
11885}
11886
11887static int
11888xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11889 xmlXPathStepOpPtr op,
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011890 xmlNodePtr * first, xmlNodePtr * last,
11891 int toBool)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011892{
11893
11894#define XP_TEST_HIT \
11895 if (hasAxisRange != 0) { \
11896 if (++pos == maxPos) { \
11897 addNode(seq, cur); \
11898 goto axis_range_end; } \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011899 } else { \
11900 addNode(seq, cur); \
11901 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011902
11903#define XP_TEST_HIT_NS \
11904 if (hasAxisRange != 0) { \
11905 if (++pos == maxPos) { \
11906 hasNsNodes = 1; \
11907 xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
11908 goto axis_range_end; } \
11909 } else { \
11910 hasNsNodes = 1; \
11911 xmlXPathNodeSetAddNs(seq, \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011912 xpctxt->node, (xmlNsPtr) cur); \
11913 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011914
11915 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11916 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11917 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11918 const xmlChar *prefix = op->value4;
11919 const xmlChar *name = op->value5;
11920 const xmlChar *URI = NULL;
11921
11922#ifdef DEBUG_STEP
11923 int nbMatches = 0, prevMatches = 0;
11924#endif
11925 int total = 0, hasNsNodes = 0;
11926 /* The popped object holding the context nodes */
11927 xmlXPathObjectPtr obj;
11928 /* The set of context nodes for the node tests */
11929 xmlNodeSetPtr contextSeq;
11930 int contextIdx;
11931 xmlNodePtr contextNode;
11932 /* The context node for a compound traversal */
11933 xmlNodePtr outerContextNode;
11934 /* The final resulting node set wrt to all context nodes */
11935 xmlNodeSetPtr outSeq;
11936 /*
11937 * The temporary resulting node set wrt 1 context node.
11938 * Used to feed predicate evaluation.
11939 */
11940 xmlNodeSetPtr seq;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011941 xmlNodePtr cur;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011942 /* First predicate operator */
11943 xmlXPathStepOpPtr predOp;
11944 int maxPos; /* The requested position() (when a "[n]" predicate) */
11945 int hasPredicateRange, hasAxisRange, pos, size, newSize;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011946 int breakOnFirstHit;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011947
11948 xmlXPathTraversalFunction next = NULL;
11949 /* compound axis traversal */
11950 xmlXPathTraversalFunctionExt outerNext = NULL;
11951 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
11952 xmlXPathNodeSetMergeFunction mergeAndClear;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011953 xmlNodePtr oldContextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011954 xmlXPathContextPtr xpctxt = ctxt->context;
11955
11956
11957 CHECK_TYPE0(XPATH_NODESET);
11958 obj = valuePop(ctxt);
11959 /*
11960 * Setup namespaces.
11961 */
11962 if (prefix != NULL) {
11963 URI = xmlXPathNsLookup(xpctxt, prefix);
11964 if (URI == NULL) {
11965 xmlXPathReleaseObject(xpctxt, obj);
11966 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11967 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000011968 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011969 /*
11970 * Setup axis.
11971 *
11972 * MAYBE FUTURE TODO: merging optimizations:
11973 * - If the nodes to be traversed wrt to the initial nodes and
11974 * the current axis cannot overlap, then we could avoid searching
11975 * for duplicates during the merge.
11976 * But the question is how/when to evaluate if they cannot overlap.
11977 * Example: if we know that for two initial nodes, the one is
11978 * not in the ancestor-or-self axis of the other, then we could safely
11979 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
11980 * the descendant-or-self axis.
11981 */
11982 addNode = xmlXPathNodeSetAdd;
11983 mergeAndClear = xmlXPathNodeSetMergeAndClear;
11984 switch (axis) {
11985 case AXIS_ANCESTOR:
11986 first = NULL;
11987 next = xmlXPathNextAncestor;
11988 break;
11989 case AXIS_ANCESTOR_OR_SELF:
11990 first = NULL;
11991 next = xmlXPathNextAncestorOrSelf;
11992 break;
11993 case AXIS_ATTRIBUTE:
11994 first = NULL;
11995 last = NULL;
11996 next = xmlXPathNextAttribute;
11997 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11998 break;
11999 case AXIS_CHILD:
12000 last = NULL;
12001 if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
12002 /*
12003 * This iterator will give us only nodes which can
12004 * hold element nodes.
12005 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000012006 outerNext = xmlXPathNextDescendantOrSelfElemParent;
12007 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012008 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12009 (type == NODE_TYPE_NODE))
12010 {
12011 /*
12012 * Optimization if an element node type is 'element'.
12013 */
12014 next = xmlXPathNextChildElement;
12015 } else
12016 next = xmlXPathNextChild;
12017 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12018 break;
12019 case AXIS_DESCENDANT:
12020 last = NULL;
12021 next = xmlXPathNextDescendant;
12022 break;
12023 case AXIS_DESCENDANT_OR_SELF:
12024 last = NULL;
12025 next = xmlXPathNextDescendantOrSelf;
12026 break;
12027 case AXIS_FOLLOWING:
12028 last = NULL;
12029 next = xmlXPathNextFollowing;
12030 break;
12031 case AXIS_FOLLOWING_SIBLING:
12032 last = NULL;
12033 next = xmlXPathNextFollowingSibling;
12034 break;
12035 case AXIS_NAMESPACE:
12036 first = NULL;
12037 last = NULL;
12038 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12039 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12040 break;
12041 case AXIS_PARENT:
12042 first = NULL;
12043 next = xmlXPathNextParent;
12044 break;
12045 case AXIS_PRECEDING:
12046 first = NULL;
12047 next = xmlXPathNextPrecedingInternal;
12048 break;
12049 case AXIS_PRECEDING_SIBLING:
12050 first = NULL;
12051 next = xmlXPathNextPrecedingSibling;
12052 break;
12053 case AXIS_SELF:
12054 first = NULL;
12055 last = NULL;
12056 next = xmlXPathNextSelf;
12057 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12058 break;
12059 }
12060
12061#ifdef DEBUG_STEP
Daniel Veillard074f37e2008-09-01 13:38:22 +000012062 xmlXPathDebugDumpStepAxis(op,
12063 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012064#endif
12065
12066 if (next == NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000012067 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012068 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012069 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012070 contextSeq = obj->nodesetval;
12071 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12072 xmlXPathReleaseObject(xpctxt, obj);
12073 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12074 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012075 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012076 /*
12077 * Predicate optimization ---------------------------------------------
12078 * If this step has a last predicate, which contains a position(),
12079 * then we'll optimize (although not exactly "position()", but only
12080 * the short-hand form, i.e., "[n]".
12081 *
12082 * Example - expression "/foo[parent::bar][1]":
Daniel Veillard45490ae2008-07-29 09:13:19 +000012083 *
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012084 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12085 * ROOT -- op->ch1
12086 * PREDICATE -- op->ch2 (predOp)
12087 * PREDICATE -- predOp->ch1 = [parent::bar]
12088 * SORT
12089 * COLLECT 'parent' 'name' 'node' bar
12090 * NODE
12091 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12092 *
12093 */
12094 maxPos = 0;
12095 predOp = NULL;
12096 hasPredicateRange = 0;
12097 hasAxisRange = 0;
12098 if (op->ch2 != -1) {
12099 /*
12100 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12101 */
12102 predOp = &ctxt->comp->steps[op->ch2];
12103 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12104 if (predOp->ch1 != -1) {
12105 /*
12106 * Use the next inner predicate operator.
12107 */
12108 predOp = &ctxt->comp->steps[predOp->ch1];
12109 hasPredicateRange = 1;
12110 } else {
12111 /*
12112 * There's no other predicate than the [n] predicate.
12113 */
12114 predOp = NULL;
12115 hasAxisRange = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012116 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012117 }
12118 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012119 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012120 /*
12121 * Axis traversal -----------------------------------------------------
12122 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012123 /*
12124 * 2.3 Node Tests
Daniel Veillard45490ae2008-07-29 09:13:19 +000012125 * - For the attribute axis, the principal node type is attribute.
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012126 * - For the namespace axis, the principal node type is namespace.
12127 * - For other axes, the principal node type is element.
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012128 *
12129 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012130 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012131 * select all element children of the context node
12132 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012133 oldContextNode = xpctxt->node;
12134 addNode = xmlXPathNodeSetAddUnique;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012135 outSeq = NULL;
12136 seq = NULL;
12137 outerContextNode = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012138 contextNode = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012139 contextIdx = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012140
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012141
12142 while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
12143 if (outerNext != NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012144 /*
12145 * This is a compound traversal.
12146 */
12147 if (contextNode == NULL) {
12148 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012149 * Set the context for the outer traversal.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012150 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012151 outerContextNode = contextSeq->nodeTab[contextIdx++];
12152 contextNode = outerNext(NULL, outerContextNode);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012153 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012154 contextNode = outerNext(contextNode, outerContextNode);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012155 if (contextNode == NULL)
12156 continue;
12157 /*
12158 * Set the context for the main traversal.
12159 */
12160 xpctxt->node = contextNode;
12161 } else
Daniel Veillard45490ae2008-07-29 09:13:19 +000012162 xpctxt->node = contextSeq->nodeTab[contextIdx++];
12163
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012164 if (seq == NULL) {
12165 seq = xmlXPathNodeSetCreate(NULL);
12166 if (seq == NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012167 total = 0;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012168 goto error;
12169 }
12170 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012171 /*
12172 * Traverse the axis and test the nodes.
12173 */
12174 pos = 0;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012175 cur = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012176 hasNsNodes = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012177 do {
12178 cur = next(ctxt, cur);
12179 if (cur == NULL)
12180 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012181
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012182 /*
12183 * QUESTION TODO: What does the "first" and "last" stuff do?
12184 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012185 if ((first != NULL) && (*first != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012186 if (*first == cur)
12187 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012188 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012189#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012190 (xmlXPathCmpNodesExt(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012191#else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012192 (xmlXPathCmpNodes(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012193#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012194 {
12195 break;
12196 }
12197 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012198 if ((last != NULL) && (*last != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012199 if (*last == cur)
12200 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012201 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012202#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012203 (xmlXPathCmpNodesExt(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012204#else
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012205 (xmlXPathCmpNodes(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012206#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012207 {
12208 break;
12209 }
12210 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012211
12212 total++;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012213
Daniel Veillardf06307e2001-07-03 10:35:50 +000012214#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012215 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12216#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +000012217
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012218 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012219 case NODE_TEST_NONE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012220 total = 0;
12221 STRANGE
12222 goto error;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012223 case NODE_TEST_TYPE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012224 /*
12225 * TODO: Don't we need to use
12226 * xmlXPathNodeSetAddNs() for namespace nodes here?
12227 * Surprisingly, some c14n tests fail, if we do this.
12228 */
12229 if (type == NODE_TYPE_NODE) {
12230 switch (cur->type) {
12231 case XML_DOCUMENT_NODE:
12232 case XML_HTML_DOCUMENT_NODE:
12233#ifdef LIBXML_DOCB_ENABLED
12234 case XML_DOCB_DOCUMENT_NODE:
12235#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +000012236 case XML_ELEMENT_NODE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012237 case XML_ATTRIBUTE_NODE:
12238 case XML_PI_NODE:
12239 case XML_COMMENT_NODE:
12240 case XML_CDATA_SECTION_NODE:
12241 case XML_TEXT_NODE:
12242 case XML_NAMESPACE_DECL:
12243 XP_TEST_HIT
12244 break;
12245 default:
12246 break;
12247 }
12248 } else if (cur->type == type) {
Kasimier T. Buchcik889b7622006-07-03 11:44:13 +000012249 if (type == XML_NAMESPACE_DECL)
12250 XP_TEST_HIT_NS
12251 else
12252 XP_TEST_HIT
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012253 } else if ((type == NODE_TYPE_TEXT) &&
12254 (cur->type == XML_CDATA_SECTION_NODE))
12255 {
12256 XP_TEST_HIT
12257 }
12258 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012259 case NODE_TEST_PI:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012260 if ((cur->type == XML_PI_NODE) &&
12261 ((name == NULL) || xmlStrEqual(name, cur->name)))
12262 {
12263 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012264 }
12265 break;
12266 case NODE_TEST_ALL:
12267 if (axis == AXIS_ATTRIBUTE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012268 if (cur->type == XML_ATTRIBUTE_NODE)
12269 {
12270 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012271 }
12272 } else if (axis == AXIS_NAMESPACE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012273 if (cur->type == XML_NAMESPACE_DECL)
12274 {
12275 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012276 }
12277 } else {
12278 if (cur->type == XML_ELEMENT_NODE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012279 if (prefix == NULL)
12280 {
12281 XP_TEST_HIT
12282
Daniel Veillardf06307e2001-07-03 10:35:50 +000012283 } else if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012284 (xmlStrEqual(URI, cur->ns->href)))
12285 {
12286 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012287 }
12288 }
12289 }
12290 break;
12291 case NODE_TEST_NS:{
12292 TODO;
12293 break;
12294 }
12295 case NODE_TEST_NAME:
Daniel Veillardfe3970e2006-11-23 16:08:30 +000012296 if (axis == AXIS_ATTRIBUTE) {
12297 if (cur->type != XML_ATTRIBUTE_NODE)
12298 break;
12299 } else if (axis == AXIS_NAMESPACE) {
12300 if (cur->type != XML_NAMESPACE_DECL)
12301 break;
12302 } else {
12303 if (cur->type != XML_ELEMENT_NODE)
12304 break;
12305 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012306 switch (cur->type) {
12307 case XML_ELEMENT_NODE:
12308 if (xmlStrEqual(name, cur->name)) {
12309 if (prefix == NULL) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012310 if (cur->ns == NULL)
12311 {
12312 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012313 }
12314 } else {
12315 if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012316 (xmlStrEqual(URI, cur->ns->href)))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012317 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012318 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012319 }
12320 }
12321 }
12322 break;
12323 case XML_ATTRIBUTE_NODE:{
12324 xmlAttrPtr attr = (xmlAttrPtr) cur;
12325
12326 if (xmlStrEqual(name, attr->name)) {
12327 if (prefix == NULL) {
12328 if ((attr->ns == NULL) ||
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012329 (attr->ns->prefix == NULL))
12330 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012331 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012332 }
12333 } else {
12334 if ((attr->ns != NULL) &&
12335 (xmlStrEqual(URI,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012336 attr->ns->href)))
12337 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012338 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012339 }
12340 }
12341 }
12342 break;
12343 }
12344 case XML_NAMESPACE_DECL:
12345 if (cur->type == XML_NAMESPACE_DECL) {
12346 xmlNsPtr ns = (xmlNsPtr) cur;
12347
12348 if ((ns->prefix != NULL) && (name != NULL)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012349 && (xmlStrEqual(ns->prefix, name)))
12350 {
12351 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012352 }
12353 }
12354 break;
12355 default:
12356 break;
12357 }
12358 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012359 } /* switch(test) */
12360 } while (cur != NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012361
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012362 goto apply_predicates;
12363
Daniel Veillard45490ae2008-07-29 09:13:19 +000012364axis_range_end: /* ----------------------------------------------------- */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012365 /*
12366 * We have a "/foo[n]", and position() = n was reached.
12367 * Note that we can have as well "/foo/::parent::foo[1]", so
12368 * a duplicate-aware merge is still needed.
12369 * Merge with the result.
12370 */
12371 if (outSeq == NULL) {
12372 outSeq = seq;
12373 seq = NULL;
12374 } else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012375 outSeq = mergeAndClear(outSeq, seq, 0);
12376 /*
12377 * Break if only a true/false result was requested.
12378 */
12379 if (toBool)
12380 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012381 continue;
12382
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012383first_hit: /* ---------------------------------------------------------- */
12384 /*
12385 * Break if only a true/false result was requested and
12386 * no predicates existed and a node test succeeded.
12387 */
12388 if (outSeq == NULL) {
12389 outSeq = seq;
12390 seq = NULL;
12391 } else
12392 outSeq = mergeAndClear(outSeq, seq, 0);
12393 break;
12394
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012395#ifdef DEBUG_STEP
12396 if (seq != NULL)
12397 nbMatches += seq->nodeNr;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012398#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012399
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012400apply_predicates: /* --------------------------------------------------- */
12401 /*
12402 * Apply predicates.
Daniel Veillard45490ae2008-07-29 09:13:19 +000012403 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012404 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12405 /*
12406 * E.g. when we have a "/foo[some expression][n]".
Daniel Veillard45490ae2008-07-29 09:13:19 +000012407 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012408 /*
12409 * QUESTION TODO: The old predicate evaluation took into
12410 * account location-sets.
12411 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12412 * Do we expect such a set here?
12413 * All what I learned now from the evaluation semantics
12414 * does not indicate that a location-set will be processed
12415 * here, so this looks OK.
Daniel Veillard45490ae2008-07-29 09:13:19 +000012416 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012417 /*
12418 * Iterate over all predicates, starting with the outermost
12419 * predicate.
12420 * TODO: Problem: we cannot execute the inner predicates first
12421 * since we cannot go back *up* the operator tree!
12422 * Options we have:
12423 * 1) Use of recursive functions (like is it currently done
12424 * via xmlXPathCompOpEval())
12425 * 2) Add a predicate evaluation information stack to the
12426 * context struct
12427 * 3) Change the way the operators are linked; we need a
12428 * "parent" field on xmlXPathStepOp
12429 *
12430 * For the moment, I'll try to solve this with a recursive
12431 * function: xmlXPathCompOpEvalPredicate().
Daniel Veillard45490ae2008-07-29 09:13:19 +000012432 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012433 size = seq->nodeNr;
12434 if (hasPredicateRange != 0)
12435 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12436 predOp, seq, size, maxPos, maxPos, hasNsNodes);
12437 else
12438 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12439 predOp, seq, size, hasNsNodes);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012440
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012441 if (ctxt->error != XPATH_EXPRESSION_OK) {
12442 total = 0;
12443 goto error;
12444 }
12445 /*
12446 * Add the filtered set of nodes to the result node set.
12447 */
12448 if (newSize == 0) {
12449 /*
12450 * The predicates filtered all nodes out.
12451 */
12452 xmlXPathNodeSetClear(seq, hasNsNodes);
12453 } else if (seq->nodeNr > 0) {
12454 /*
12455 * Add to result set.
12456 */
12457 if (outSeq == NULL) {
12458 if (size != newSize) {
12459 /*
12460 * We need to merge and clear here, since
12461 * the sequence will contained NULLed entries.
12462 */
12463 outSeq = mergeAndClear(NULL, seq, 1);
12464 } else {
12465 outSeq = seq;
12466 seq = NULL;
12467 }
12468 } else
12469 outSeq = mergeAndClear(outSeq, seq,
12470 (size != newSize) ? 1: 0);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012471 /*
12472 * Break if only a true/false result was requested.
12473 */
12474 if (toBool)
12475 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012476 }
12477 } else if (seq->nodeNr > 0) {
12478 /*
12479 * Add to result set.
12480 */
12481 if (outSeq == NULL) {
12482 outSeq = seq;
12483 seq = NULL;
12484 } else {
12485 outSeq = mergeAndClear(outSeq, seq, 0);
12486 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012487 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012488 }
12489
12490error:
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012491 if ((obj->boolval) && (obj->user != NULL)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012492 /*
12493 * QUESTION TODO: What does this do and why?
12494 * TODO: Do we have to do this also for the "error"
12495 * cleanup further down?
12496 */
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012497 ctxt->value->boolval = 1;
12498 ctxt->value->user = obj->user;
12499 obj->user = NULL;
12500 obj->boolval = 0;
12501 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012502 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012503
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012504 /*
12505 * Ensure we return at least an emtpy set.
12506 */
12507 if (outSeq == NULL) {
12508 if ((seq != NULL) && (seq->nodeNr == 0))
12509 outSeq = seq;
12510 else
12511 outSeq = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +000012512 /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012513 }
12514 if ((seq != NULL) && (seq != outSeq)) {
12515 xmlXPathFreeNodeSet(seq);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012516 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012517 /*
12518 * Hand over the result. Better to push the set also in
12519 * case of errors.
12520 */
12521 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12522 /*
12523 * Reset the context node.
12524 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012525 xpctxt->node = oldContextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012526
12527#ifdef DEBUG_STEP
12528 xmlGenericError(xmlGenericErrorContext,
12529 "\nExamined %d nodes, found %d nodes at that step\n",
12530 total, nbMatches);
12531#endif
12532
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012533 return(total);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012534}
12535
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012536static int
12537xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12538 xmlXPathStepOpPtr op, xmlNodePtr * first);
12539
Daniel Veillardf06307e2001-07-03 10:35:50 +000012540/**
12541 * xmlXPathCompOpEvalFirst:
12542 * @ctxt: the XPath parser context with the compiled expression
12543 * @op: an XPath compiled operation
12544 * @first: the first elem found so far
12545 *
12546 * Evaluate the Precompiled XPath operation searching only the first
12547 * element in document order
12548 *
12549 * Returns the number of examined objects.
12550 */
12551static int
12552xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12553 xmlXPathStepOpPtr op, xmlNodePtr * first)
12554{
12555 int total = 0, cur;
12556 xmlXPathCompExprPtr comp;
12557 xmlXPathObjectPtr arg1, arg2;
12558
Daniel Veillard556c6682001-10-06 09:59:51 +000012559 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012560 comp = ctxt->comp;
12561 switch (op->op) {
12562 case XPATH_OP_END:
12563 return (0);
12564 case XPATH_OP_UNION:
12565 total =
12566 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12567 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012568 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012569 if ((ctxt->value != NULL)
12570 && (ctxt->value->type == XPATH_NODESET)
12571 && (ctxt->value->nodesetval != NULL)
12572 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12573 /*
12574 * limit tree traversing to first node in the result
12575 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012576 /*
12577 * OPTIMIZE TODO: This implicitely sorts
12578 * the result, even if not needed. E.g. if the argument
12579 * of the count() function, no sorting is needed.
12580 * OPTIMIZE TODO: How do we know if the node-list wasn't
12581 * aready sorted?
12582 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012583 if (ctxt->value->nodesetval->nodeNr > 1)
12584 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012585 *first = ctxt->value->nodesetval->nodeTab[0];
12586 }
12587 cur =
12588 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12589 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012590 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012591 CHECK_TYPE0(XPATH_NODESET);
12592 arg2 = valuePop(ctxt);
12593
12594 CHECK_TYPE0(XPATH_NODESET);
12595 arg1 = valuePop(ctxt);
12596
12597 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12598 arg2->nodesetval);
12599 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012600 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012601 /* optimizer */
12602 if (total > cur)
12603 xmlXPathCompSwap(op);
12604 return (total + cur);
12605 case XPATH_OP_ROOT:
12606 xmlXPathRoot(ctxt);
12607 return (0);
12608 case XPATH_OP_NODE:
12609 if (op->ch1 != -1)
12610 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012611 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012612 if (op->ch2 != -1)
12613 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012614 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012615 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12616 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012617 return (total);
12618 case XPATH_OP_RESET:
12619 if (op->ch1 != -1)
12620 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012621 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012622 if (op->ch2 != -1)
12623 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012624 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012625 ctxt->context->node = NULL;
12626 return (total);
12627 case XPATH_OP_COLLECT:{
12628 if (op->ch1 == -1)
12629 return (total);
12630
12631 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012632 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012633
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012634 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012635 return (total);
12636 }
12637 case XPATH_OP_VALUE:
12638 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012639 xmlXPathCacheObjectCopy(ctxt->context,
12640 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012641 return (0);
12642 case XPATH_OP_SORT:
12643 if (op->ch1 != -1)
12644 total +=
12645 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12646 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012647 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012648 if ((ctxt->value != NULL)
12649 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012650 && (ctxt->value->nodesetval != NULL)
12651 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012652 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12653 return (total);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012654#ifdef XP_OPTIMIZED_FILTER_FIRST
12655 case XPATH_OP_FILTER:
12656 total =+ xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12657 return (total);
12658#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000012659 default:
12660 return (xmlXPathCompOpEval(ctxt, op));
12661 }
12662}
12663
12664/**
12665 * xmlXPathCompOpEvalLast:
12666 * @ctxt: the XPath parser context with the compiled expression
12667 * @op: an XPath compiled operation
12668 * @last: the last elem found so far
12669 *
12670 * Evaluate the Precompiled XPath operation searching only the last
12671 * element in document order
12672 *
William M. Brack08171912003-12-29 02:52:11 +000012673 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000012674 */
12675static int
12676xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12677 xmlNodePtr * last)
12678{
12679 int total = 0, cur;
12680 xmlXPathCompExprPtr comp;
12681 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +000012682 xmlNodePtr bak;
12683 xmlDocPtr bakd;
12684 int pp;
12685 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012686
Daniel Veillard556c6682001-10-06 09:59:51 +000012687 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012688 comp = ctxt->comp;
12689 switch (op->op) {
12690 case XPATH_OP_END:
12691 return (0);
12692 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +000012693 bakd = ctxt->context->doc;
12694 bak = ctxt->context->node;
12695 pp = ctxt->context->proximityPosition;
12696 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012697 total =
12698 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012699 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012700 if ((ctxt->value != NULL)
12701 && (ctxt->value->type == XPATH_NODESET)
12702 && (ctxt->value->nodesetval != NULL)
12703 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12704 /*
12705 * limit tree traversing to first node in the result
12706 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012707 if (ctxt->value->nodesetval->nodeNr > 1)
12708 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012709 *last =
12710 ctxt->value->nodesetval->nodeTab[ctxt->value->
12711 nodesetval->nodeNr -
12712 1];
12713 }
William M. Brackce4fc562004-01-22 02:47:18 +000012714 ctxt->context->doc = bakd;
12715 ctxt->context->node = bak;
12716 ctxt->context->proximityPosition = pp;
12717 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012718 cur =
12719 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012720 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012721 if ((ctxt->value != NULL)
12722 && (ctxt->value->type == XPATH_NODESET)
12723 && (ctxt->value->nodesetval != NULL)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012724 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012725 }
12726 CHECK_TYPE0(XPATH_NODESET);
12727 arg2 = valuePop(ctxt);
12728
12729 CHECK_TYPE0(XPATH_NODESET);
12730 arg1 = valuePop(ctxt);
12731
12732 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12733 arg2->nodesetval);
12734 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012735 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012736 /* optimizer */
12737 if (total > cur)
12738 xmlXPathCompSwap(op);
12739 return (total + cur);
12740 case XPATH_OP_ROOT:
12741 xmlXPathRoot(ctxt);
12742 return (0);
12743 case XPATH_OP_NODE:
12744 if (op->ch1 != -1)
12745 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012746 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012747 if (op->ch2 != -1)
12748 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012749 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012750 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12751 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012752 return (total);
12753 case XPATH_OP_RESET:
12754 if (op->ch1 != -1)
12755 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012756 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012757 if (op->ch2 != -1)
12758 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012759 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012760 ctxt->context->node = NULL;
12761 return (total);
12762 case XPATH_OP_COLLECT:{
12763 if (op->ch1 == -1)
12764 return (0);
12765
12766 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012767 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012768
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012769 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012770 return (total);
12771 }
12772 case XPATH_OP_VALUE:
12773 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012774 xmlXPathCacheObjectCopy(ctxt->context,
12775 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012776 return (0);
12777 case XPATH_OP_SORT:
12778 if (op->ch1 != -1)
12779 total +=
12780 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12781 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012782 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012783 if ((ctxt->value != NULL)
12784 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012785 && (ctxt->value->nodesetval != NULL)
12786 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012787 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12788 return (total);
12789 default:
12790 return (xmlXPathCompOpEval(ctxt, op));
12791 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012792}
12793
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012794#ifdef XP_OPTIMIZED_FILTER_FIRST
12795static int
12796xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12797 xmlXPathStepOpPtr op, xmlNodePtr * first)
12798{
12799 int total = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012800 xmlXPathCompExprPtr comp;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012801 xmlXPathObjectPtr res;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012802 xmlXPathObjectPtr obj;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012803 xmlNodeSetPtr oldset;
12804 xmlNodePtr oldnode;
12805 xmlDocPtr oldDoc;
12806 int i;
12807
12808 CHECK_ERROR0;
12809 comp = ctxt->comp;
12810 /*
12811 * Optimization for ()[last()] selection i.e. the last elem
12812 */
12813 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12814 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12815 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12816 int f = comp->steps[op->ch2].ch1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012817
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012818 if ((f != -1) &&
12819 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12820 (comp->steps[f].value5 == NULL) &&
12821 (comp->steps[f].value == 0) &&
12822 (comp->steps[f].value4 != NULL) &&
12823 (xmlStrEqual
12824 (comp->steps[f].value4, BAD_CAST "last"))) {
12825 xmlNodePtr last = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012826
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012827 total +=
12828 xmlXPathCompOpEvalLast(ctxt,
12829 &comp->steps[op->ch1],
12830 &last);
12831 CHECK_ERROR0;
12832 /*
12833 * The nodeset should be in document order,
12834 * Keep only the last value
12835 */
12836 if ((ctxt->value != NULL) &&
12837 (ctxt->value->type == XPATH_NODESET) &&
12838 (ctxt->value->nodesetval != NULL) &&
12839 (ctxt->value->nodesetval->nodeTab != NULL) &&
12840 (ctxt->value->nodesetval->nodeNr > 1)) {
12841 ctxt->value->nodesetval->nodeTab[0] =
12842 ctxt->value->nodesetval->nodeTab[ctxt->
12843 value->
12844 nodesetval->
12845 nodeNr -
12846 1];
12847 ctxt->value->nodesetval->nodeNr = 1;
12848 *first = *(ctxt->value->nodesetval->nodeTab);
12849 }
12850 return (total);
12851 }
12852 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012853
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012854 if (op->ch1 != -1)
12855 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12856 CHECK_ERROR0;
12857 if (op->ch2 == -1)
12858 return (total);
12859 if (ctxt->value == NULL)
12860 return (total);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012861
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012862#ifdef LIBXML_XPTR_ENABLED
12863 oldnode = ctxt->context->node;
12864 /*
12865 * Hum are we filtering the result of an XPointer expression
12866 */
12867 if (ctxt->value->type == XPATH_LOCATIONSET) {
12868 xmlXPathObjectPtr tmp = NULL;
12869 xmlLocationSetPtr newlocset = NULL;
12870 xmlLocationSetPtr oldlocset;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012871
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012872 /*
12873 * Extract the old locset, and then evaluate the result of the
12874 * expression for all the element in the locset. use it to grow
12875 * up a new locset.
12876 */
12877 CHECK_TYPE0(XPATH_LOCATIONSET);
12878 obj = valuePop(ctxt);
12879 oldlocset = obj->user;
12880 ctxt->context->node = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012881
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012882 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12883 ctxt->context->contextSize = 0;
12884 ctxt->context->proximityPosition = 0;
12885 if (op->ch2 != -1)
12886 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12887 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012888 if (res != NULL) {
12889 xmlXPathReleaseObject(ctxt->context, res);
12890 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012891 valuePush(ctxt, obj);
12892 CHECK_ERROR0;
12893 return (total);
12894 }
12895 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012896
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012897 for (i = 0; i < oldlocset->locNr; i++) {
12898 /*
12899 * Run the evaluation with a node list made of a
12900 * single item in the nodelocset.
12901 */
12902 ctxt->context->node = oldlocset->locTab[i]->user;
12903 ctxt->context->contextSize = oldlocset->locNr;
12904 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012905 if (tmp == NULL) {
12906 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12907 ctxt->context->node);
12908 } else {
12909 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12910 ctxt->context->node);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012911 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012912 valuePush(ctxt, tmp);
12913 if (op->ch2 != -1)
12914 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12915 if (ctxt->error != XPATH_EXPRESSION_OK) {
12916 xmlXPathFreeObject(obj);
12917 return(0);
12918 }
12919 /*
12920 * The result of the evaluation need to be tested to
12921 * decided whether the filter succeeded or not
12922 */
12923 res = valuePop(ctxt);
12924 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12925 xmlXPtrLocationSetAdd(newlocset,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012926 xmlXPathCacheObjectCopy(ctxt->context,
12927 oldlocset->locTab[i]));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012928 }
12929 /*
12930 * Cleanup
12931 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012932 if (res != NULL) {
12933 xmlXPathReleaseObject(ctxt->context, res);
12934 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012935 if (ctxt->value == tmp) {
12936 valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012937 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012938 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012939 * REVISIT TODO: Don't create a temporary nodeset
12940 * for everly iteration.
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012941 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012942 /* OLD: xmlXPathFreeObject(res); */
12943 } else
Daniel Veillard45490ae2008-07-29 09:13:19 +000012944 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012945 ctxt->context->node = NULL;
12946 /*
12947 * Only put the first node in the result, then leave.
12948 */
12949 if (newlocset->locNr > 0) {
12950 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
12951 break;
12952 }
12953 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012954 if (tmp != NULL) {
12955 xmlXPathReleaseObject(ctxt->context, tmp);
12956 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012957 /*
12958 * The result is used as the new evaluation locset.
12959 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012960 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012961 ctxt->context->node = NULL;
12962 ctxt->context->contextSize = -1;
12963 ctxt->context->proximityPosition = -1;
12964 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12965 ctxt->context->node = oldnode;
12966 return (total);
12967 }
12968#endif /* LIBXML_XPTR_ENABLED */
Daniel Veillard45490ae2008-07-29 09:13:19 +000012969
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012970 /*
12971 * Extract the old set, and then evaluate the result of the
12972 * expression for all the element in the set. use it to grow
12973 * up a new set.
12974 */
12975 CHECK_TYPE0(XPATH_NODESET);
12976 obj = valuePop(ctxt);
12977 oldset = obj->nodesetval;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012978
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012979 oldnode = ctxt->context->node;
12980 oldDoc = ctxt->context->doc;
12981 ctxt->context->node = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012982
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012983 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
12984 ctxt->context->contextSize = 0;
12985 ctxt->context->proximityPosition = 0;
12986 /* QUESTION TODO: Why was this code commented out?
12987 if (op->ch2 != -1)
12988 total +=
12989 xmlXPathCompOpEval(ctxt,
12990 &comp->steps[op->ch2]);
12991 CHECK_ERROR0;
12992 res = valuePop(ctxt);
12993 if (res != NULL)
12994 xmlXPathFreeObject(res);
12995 */
12996 valuePush(ctxt, obj);
12997 ctxt->context->node = oldnode;
12998 CHECK_ERROR0;
12999 } else {
13000 xmlNodeSetPtr newset;
13001 xmlXPathObjectPtr tmp = NULL;
13002 /*
13003 * Initialize the new set.
13004 * Also set the xpath document in case things like
13005 * key() evaluation are attempted on the predicate
Daniel Veillard45490ae2008-07-29 09:13:19 +000013006 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013007 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +000013008 /* XXX what if xmlXPathNodeSetCreate returned NULL? */
Daniel Veillard45490ae2008-07-29 09:13:19 +000013009
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013010 for (i = 0; i < oldset->nodeNr; i++) {
13011 /*
13012 * Run the evaluation with a node list made of
13013 * a single item in the nodeset.
13014 */
13015 ctxt->context->node = oldset->nodeTab[i];
13016 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13017 (oldset->nodeTab[i]->doc != NULL))
13018 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013019 if (tmp == NULL) {
13020 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13021 ctxt->context->node);
13022 } else {
13023 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13024 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013025 }
13026 valuePush(ctxt, tmp);
13027 ctxt->context->contextSize = oldset->nodeNr;
13028 ctxt->context->proximityPosition = i + 1;
13029 if (op->ch2 != -1)
13030 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13031 if (ctxt->error != XPATH_EXPRESSION_OK) {
13032 xmlXPathFreeNodeSet(newset);
13033 xmlXPathFreeObject(obj);
13034 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013035 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013036 /*
13037 * The result of the evaluation needs to be tested to
13038 * decide whether the filter succeeded or not
13039 */
13040 res = valuePop(ctxt);
13041 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13042 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013043 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013044 /*
13045 * Cleanup
13046 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013047 if (res != NULL) {
13048 xmlXPathReleaseObject(ctxt->context, res);
13049 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013050 if (ctxt->value == tmp) {
13051 valuePop(ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013052 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013053 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013054 * in order to avoid massive recreation inside this
13055 * loop.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013056 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000013057 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013058 } else
13059 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013060 ctxt->context->node = NULL;
13061 /*
13062 * Only put the first node in the result, then leave.
13063 */
13064 if (newset->nodeNr > 0) {
13065 *first = *(newset->nodeTab);
13066 break;
13067 }
13068 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013069 if (tmp != NULL) {
13070 xmlXPathReleaseObject(ctxt->context, tmp);
13071 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013072 /*
13073 * The result is used as the new evaluation set.
13074 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013075 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013076 ctxt->context->node = NULL;
13077 ctxt->context->contextSize = -1;
13078 ctxt->context->proximityPosition = -1;
13079 /* may want to move this past the '}' later */
13080 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013081 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013082 }
13083 ctxt->context->node = oldnode;
13084 return(total);
13085}
13086#endif /* XP_OPTIMIZED_FILTER_FIRST */
13087
Owen Taylor3473f882001-02-23 17:55:21 +000013088/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013089 * xmlXPathCompOpEval:
13090 * @ctxt: the XPath parser context with the compiled expression
13091 * @op: an XPath compiled operation
13092 *
13093 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000013094 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013095 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013096static int
13097xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13098{
13099 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013100 int equal, ret;
13101 xmlXPathCompExprPtr comp;
13102 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013103 xmlNodePtr bak;
13104 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000013105 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000013106 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013107
Daniel Veillard556c6682001-10-06 09:59:51 +000013108 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013109 comp = ctxt->comp;
13110 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013111 case XPATH_OP_END:
13112 return (0);
13113 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013114 bakd = ctxt->context->doc;
13115 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013116 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013117 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013118 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013119 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013120 xmlXPathBooleanFunction(ctxt, 1);
13121 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13122 return (total);
13123 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013124 ctxt->context->doc = bakd;
13125 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013126 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013127 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013128 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013129 if (ctxt->error) {
13130 xmlXPathFreeObject(arg2);
13131 return(0);
13132 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013133 xmlXPathBooleanFunction(ctxt, 1);
13134 arg1 = valuePop(ctxt);
13135 arg1->boolval &= arg2->boolval;
13136 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013137 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013138 return (total);
13139 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013140 bakd = ctxt->context->doc;
13141 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013142 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013143 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013144 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013145 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013146 xmlXPathBooleanFunction(ctxt, 1);
13147 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13148 return (total);
13149 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013150 ctxt->context->doc = bakd;
13151 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013152 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013153 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013154 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013155 if (ctxt->error) {
13156 xmlXPathFreeObject(arg2);
13157 return(0);
13158 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013159 xmlXPathBooleanFunction(ctxt, 1);
13160 arg1 = valuePop(ctxt);
13161 arg1->boolval |= arg2->boolval;
13162 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013163 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013164 return (total);
13165 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013166 bakd = ctxt->context->doc;
13167 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013168 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013169 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013170 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013171 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013172 ctxt->context->doc = bakd;
13173 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013174 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013175 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013176 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013177 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000013178 if (op->value)
Daniel Veillard45490ae2008-07-29 09:13:19 +000013179 equal = xmlXPathEqualValues(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +000013180 else
13181 equal = xmlXPathNotEqualValues(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013182 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013183 return (total);
13184 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013185 bakd = ctxt->context->doc;
13186 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013187 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013188 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013189 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013190 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013191 ctxt->context->doc = bakd;
13192 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013193 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013194 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013195 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013196 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013197 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013198 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013199 return (total);
13200 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013201 bakd = ctxt->context->doc;
13202 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013203 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013204 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013205 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013206 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013207 if (op->ch2 != -1) {
13208 ctxt->context->doc = bakd;
13209 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013210 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013211 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013212 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013213 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013214 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013215 if (op->value == 0)
13216 xmlXPathSubValues(ctxt);
13217 else if (op->value == 1)
13218 xmlXPathAddValues(ctxt);
13219 else if (op->value == 2)
13220 xmlXPathValueFlipSign(ctxt);
13221 else if (op->value == 3) {
13222 CAST_TO_NUMBER;
13223 CHECK_TYPE0(XPATH_NUMBER);
13224 }
13225 return (total);
13226 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013227 bakd = ctxt->context->doc;
13228 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013229 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013230 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013231 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013232 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013233 ctxt->context->doc = bakd;
13234 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013235 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013236 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013237 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013238 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013239 if (op->value == 0)
13240 xmlXPathMultValues(ctxt);
13241 else if (op->value == 1)
13242 xmlXPathDivValues(ctxt);
13243 else if (op->value == 2)
13244 xmlXPathModValues(ctxt);
13245 return (total);
13246 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013247 bakd = ctxt->context->doc;
13248 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013249 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013250 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013251 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013252 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013253 ctxt->context->doc = bakd;
13254 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013255 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013256 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013257 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013258 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013259 CHECK_TYPE0(XPATH_NODESET);
13260 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013261
Daniel Veillardf06307e2001-07-03 10:35:50 +000013262 CHECK_TYPE0(XPATH_NODESET);
13263 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013264
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013265 if ((arg1->nodesetval == NULL) ||
13266 ((arg2->nodesetval != NULL) &&
13267 (arg2->nodesetval->nodeNr != 0)))
13268 {
13269 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13270 arg2->nodesetval);
13271 }
13272
Daniel Veillardf06307e2001-07-03 10:35:50 +000013273 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013274 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013275 return (total);
13276 case XPATH_OP_ROOT:
13277 xmlXPathRoot(ctxt);
13278 return (total);
13279 case XPATH_OP_NODE:
13280 if (op->ch1 != -1)
13281 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013282 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013283 if (op->ch2 != -1)
13284 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013285 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013286 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13287 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013288 return (total);
13289 case XPATH_OP_RESET:
13290 if (op->ch1 != -1)
13291 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013292 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013293 if (op->ch2 != -1)
13294 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013295 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013296 ctxt->context->node = NULL;
13297 return (total);
13298 case XPATH_OP_COLLECT:{
13299 if (op->ch1 == -1)
13300 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000013301
Daniel Veillardf06307e2001-07-03 10:35:50 +000013302 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013303 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013304
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013305 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013306 return (total);
13307 }
13308 case XPATH_OP_VALUE:
13309 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013310 xmlXPathCacheObjectCopy(ctxt->context,
13311 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013312 return (total);
13313 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000013314 xmlXPathObjectPtr val;
13315
Daniel Veillardf06307e2001-07-03 10:35:50 +000013316 if (op->ch1 != -1)
13317 total +=
13318 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013319 if (op->value5 == NULL) {
13320 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13321 if (val == NULL) {
13322 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13323 return(0);
13324 }
13325 valuePush(ctxt, val);
13326 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013327 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013328
Daniel Veillardf06307e2001-07-03 10:35:50 +000013329 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13330 if (URI == NULL) {
13331 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013332 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13333 (char *) op->value4, (char *)op->value5);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013334 return (total);
13335 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013336 val = xmlXPathVariableLookupNS(ctxt->context,
13337 op->value4, URI);
13338 if (val == NULL) {
13339 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13340 return(0);
13341 }
13342 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013343 }
13344 return (total);
13345 }
13346 case XPATH_OP_FUNCTION:{
13347 xmlXPathFunction func;
13348 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000013349 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013350
13351 if (op->ch1 != -1)
13352 total +=
13353 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013354 if (ctxt->valueNr < op->value) {
13355 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013356 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013357 ctxt->error = XPATH_INVALID_OPERAND;
13358 return (total);
13359 }
13360 for (i = 0; i < op->value; i++)
13361 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13362 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013363 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013364 ctxt->error = XPATH_INVALID_OPERAND;
13365 return (total);
13366 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013367 if (op->cache != NULL)
William M. Brackad0e67c2004-12-01 14:35:10 +000013368 XML_CAST_FPTR(func) = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013369 else {
13370 const xmlChar *URI = NULL;
13371
13372 if (op->value5 == NULL)
13373 func =
13374 xmlXPathFunctionLookup(ctxt->context,
13375 op->value4);
13376 else {
13377 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13378 if (URI == NULL) {
13379 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013380 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13381 (char *)op->value4, (char *)op->value5);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013382 return (total);
13383 }
13384 func = xmlXPathFunctionLookupNS(ctxt->context,
13385 op->value4, URI);
13386 }
13387 if (func == NULL) {
13388 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013389 "xmlXPathCompOpEval: function %s not found\n",
13390 (char *)op->value4);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013391 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013392 }
William M. Brackad0e67c2004-12-01 14:35:10 +000013393 op->cache = XML_CAST_FPTR(func);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013394 op->cacheURI = (void *) URI;
13395 }
13396 oldFunc = ctxt->context->function;
13397 oldFuncURI = ctxt->context->functionURI;
13398 ctxt->context->function = op->value4;
13399 ctxt->context->functionURI = op->cacheURI;
13400 func(ctxt, op->value);
13401 ctxt->context->function = oldFunc;
13402 ctxt->context->functionURI = oldFuncURI;
13403 return (total);
13404 }
13405 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000013406 bakd = ctxt->context->doc;
13407 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000013408 pp = ctxt->context->proximityPosition;
13409 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013410 if (op->ch1 != -1)
13411 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
William M. Brack645a9242004-11-09 12:20:42 +000013412 ctxt->context->contextSize = cs;
13413 ctxt->context->proximityPosition = pp;
Daniel Veillard088bf112002-05-14 11:03:59 +000013414 ctxt->context->node = bak;
William M. Brack645a9242004-11-09 12:20:42 +000013415 ctxt->context->doc = bakd;
Daniel Veillard556c6682001-10-06 09:59:51 +000013416 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000013417 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013418 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000013419 ctxt->context->doc = bakd;
13420 ctxt->context->node = bak;
13421 CHECK_ERROR0;
13422 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013423 return (total);
13424 case XPATH_OP_PREDICATE:
13425 case XPATH_OP_FILTER:{
13426 xmlXPathObjectPtr res;
13427 xmlXPathObjectPtr obj, tmp;
13428 xmlNodeSetPtr newset = NULL;
13429 xmlNodeSetPtr oldset;
13430 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000013431 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013432 int i;
13433
13434 /*
13435 * Optimization for ()[1] selection i.e. the first elem
13436 */
13437 if ((op->ch1 != -1) && (op->ch2 != -1) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013438#ifdef XP_OPTIMIZED_FILTER_FIRST
13439 /*
13440 * FILTER TODO: Can we assume that the inner processing
13441 * will result in an ordered list if we have an
13442 * XPATH_OP_FILTER?
13443 * What about an additional field or flag on
13444 * xmlXPathObject like @sorted ? This way we wouln'd need
13445 * to assume anything, so it would be more robust and
13446 * easier to optimize.
13447 */
13448 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13449 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13450#else
13451 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13452#endif
13453 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013454 xmlXPathObjectPtr val;
13455
13456 val = comp->steps[op->ch2].value4;
13457 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13458 (val->floatval == 1.0)) {
13459 xmlNodePtr first = NULL;
13460
13461 total +=
13462 xmlXPathCompOpEvalFirst(ctxt,
13463 &comp->steps[op->ch1],
13464 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000013465 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013466 /*
13467 * The nodeset should be in document order,
13468 * Keep only the first value
13469 */
13470 if ((ctxt->value != NULL) &&
13471 (ctxt->value->type == XPATH_NODESET) &&
13472 (ctxt->value->nodesetval != NULL) &&
13473 (ctxt->value->nodesetval->nodeNr > 1))
13474 ctxt->value->nodesetval->nodeNr = 1;
13475 return (total);
13476 }
13477 }
13478 /*
13479 * Optimization for ()[last()] selection i.e. the last elem
13480 */
13481 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13482 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13483 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13484 int f = comp->steps[op->ch2].ch1;
13485
13486 if ((f != -1) &&
13487 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13488 (comp->steps[f].value5 == NULL) &&
13489 (comp->steps[f].value == 0) &&
13490 (comp->steps[f].value4 != NULL) &&
13491 (xmlStrEqual
13492 (comp->steps[f].value4, BAD_CAST "last"))) {
13493 xmlNodePtr last = NULL;
13494
13495 total +=
13496 xmlXPathCompOpEvalLast(ctxt,
13497 &comp->steps[op->ch1],
13498 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000013499 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013500 /*
13501 * The nodeset should be in document order,
13502 * Keep only the last value
13503 */
13504 if ((ctxt->value != NULL) &&
13505 (ctxt->value->type == XPATH_NODESET) &&
13506 (ctxt->value->nodesetval != NULL) &&
13507 (ctxt->value->nodesetval->nodeTab != NULL) &&
13508 (ctxt->value->nodesetval->nodeNr > 1)) {
13509 ctxt->value->nodesetval->nodeTab[0] =
13510 ctxt->value->nodesetval->nodeTab[ctxt->
13511 value->
13512 nodesetval->
13513 nodeNr -
13514 1];
13515 ctxt->value->nodesetval->nodeNr = 1;
13516 }
13517 return (total);
13518 }
13519 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013520 /*
13521 * Process inner predicates first.
13522 * Example "index[parent::book][1]":
13523 * ...
13524 * PREDICATE <-- we are here "[1]"
13525 * PREDICATE <-- process "[parent::book]" first
13526 * SORT
13527 * COLLECT 'parent' 'name' 'node' book
13528 * NODE
13529 * ELEM Object is a number : 1
13530 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013531 if (op->ch1 != -1)
13532 total +=
13533 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013534 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013535 if (op->ch2 == -1)
13536 return (total);
13537 if (ctxt->value == NULL)
13538 return (total);
13539
13540 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013541
13542#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013543 /*
13544 * Hum are we filtering the result of an XPointer expression
13545 */
13546 if (ctxt->value->type == XPATH_LOCATIONSET) {
13547 xmlLocationSetPtr newlocset = NULL;
13548 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013549
Daniel Veillardf06307e2001-07-03 10:35:50 +000013550 /*
13551 * Extract the old locset, and then evaluate the result of the
13552 * expression for all the element in the locset. use it to grow
13553 * up a new locset.
13554 */
13555 CHECK_TYPE0(XPATH_LOCATIONSET);
13556 obj = valuePop(ctxt);
13557 oldlocset = obj->user;
13558 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013559
Daniel Veillardf06307e2001-07-03 10:35:50 +000013560 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13561 ctxt->context->contextSize = 0;
13562 ctxt->context->proximityPosition = 0;
13563 if (op->ch2 != -1)
13564 total +=
13565 xmlXPathCompOpEval(ctxt,
13566 &comp->steps[op->ch2]);
13567 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013568 if (res != NULL) {
13569 xmlXPathReleaseObject(ctxt->context, res);
13570 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013571 valuePush(ctxt, obj);
13572 CHECK_ERROR0;
13573 return (total);
13574 }
13575 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013576
Daniel Veillardf06307e2001-07-03 10:35:50 +000013577 for (i = 0; i < oldlocset->locNr; i++) {
13578 /*
13579 * Run the evaluation with a node list made of a
13580 * single item in the nodelocset.
13581 */
13582 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013583 ctxt->context->contextSize = oldlocset->locNr;
13584 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013585 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13586 ctxt->context->node);
William M. Brackf7eb7942003-12-31 07:59:17 +000013587 valuePush(ctxt, tmp);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013588
Daniel Veillardf06307e2001-07-03 10:35:50 +000013589 if (op->ch2 != -1)
13590 total +=
13591 xmlXPathCompOpEval(ctxt,
13592 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013593 if (ctxt->error != XPATH_EXPRESSION_OK) {
13594 xmlXPathFreeObject(obj);
13595 return(0);
13596 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013597
Daniel Veillardf06307e2001-07-03 10:35:50 +000013598 /*
13599 * The result of the evaluation need to be tested to
13600 * decided whether the filter succeeded or not
13601 */
13602 res = valuePop(ctxt);
13603 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13604 xmlXPtrLocationSetAdd(newlocset,
13605 xmlXPathObjectCopy
13606 (oldlocset->locTab[i]));
13607 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013608
Daniel Veillardf06307e2001-07-03 10:35:50 +000013609 /*
13610 * Cleanup
13611 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013612 if (res != NULL) {
13613 xmlXPathReleaseObject(ctxt->context, res);
13614 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013615 if (ctxt->value == tmp) {
13616 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013617 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013618 }
13619
13620 ctxt->context->node = NULL;
13621 }
13622
13623 /*
13624 * The result is used as the new evaluation locset.
13625 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013626 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013627 ctxt->context->node = NULL;
13628 ctxt->context->contextSize = -1;
13629 ctxt->context->proximityPosition = -1;
13630 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13631 ctxt->context->node = oldnode;
13632 return (total);
13633 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013634#endif /* LIBXML_XPTR_ENABLED */
13635
Daniel Veillardf06307e2001-07-03 10:35:50 +000013636 /*
13637 * Extract the old set, and then evaluate the result of the
13638 * expression for all the element in the set. use it to grow
13639 * up a new set.
13640 */
13641 CHECK_TYPE0(XPATH_NODESET);
13642 obj = valuePop(ctxt);
13643 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000013644
Daniel Veillardf06307e2001-07-03 10:35:50 +000013645 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000013646 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013647 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013648
Daniel Veillardf06307e2001-07-03 10:35:50 +000013649 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13650 ctxt->context->contextSize = 0;
13651 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000013652/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000013653 if (op->ch2 != -1)
13654 total +=
13655 xmlXPathCompOpEval(ctxt,
13656 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013657 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013658 res = valuePop(ctxt);
13659 if (res != NULL)
13660 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000013661*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000013662 valuePush(ctxt, obj);
13663 ctxt->context->node = oldnode;
13664 CHECK_ERROR0;
13665 } else {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013666 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013667 /*
13668 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000013669 * Also set the xpath document in case things like
13670 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000013671 */
13672 newset = xmlXPathNodeSetCreate(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013673 /*
13674 * SPEC XPath 1.0:
13675 * "For each node in the node-set to be filtered, the
13676 * PredicateExpr is evaluated with that node as the
13677 * context node, with the number of nodes in the
13678 * node-set as the context size, and with the proximity
13679 * position of the node in the node-set with respect to
13680 * the axis as the context position;"
13681 * @oldset is the node-set" to be filtered.
13682 *
13683 * SPEC XPath 1.0:
13684 * "only predicates change the context position and
13685 * context size (see [2.4 Predicates])."
13686 * Example:
13687 * node-set context pos
13688 * nA 1
13689 * nB 2
13690 * nC 3
13691 * After applying predicate [position() > 1] :
13692 * node-set context pos
13693 * nB 1
13694 * nC 2
13695 *
13696 * removed the first node in the node-set, then
Daniel Veillard45490ae2008-07-29 09:13:19 +000013697 * the context position of the
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013698 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013699 for (i = 0; i < oldset->nodeNr; i++) {
13700 /*
13701 * Run the evaluation with a node list made of
13702 * a single item in the nodeset.
13703 */
13704 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000013705 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13706 (oldset->nodeTab[i]->doc != NULL))
13707 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013708 if (tmp == NULL) {
13709 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13710 ctxt->context->node);
13711 } else {
13712 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13713 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013714 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013715 valuePush(ctxt, tmp);
13716 ctxt->context->contextSize = oldset->nodeNr;
13717 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013718 /*
13719 * Evaluate the predicate against the context node.
13720 * Can/should we optimize position() predicates
13721 * here (e.g. "[1]")?
13722 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013723 if (op->ch2 != -1)
13724 total +=
13725 xmlXPathCompOpEval(ctxt,
13726 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013727 if (ctxt->error != XPATH_EXPRESSION_OK) {
13728 xmlXPathFreeNodeSet(newset);
13729 xmlXPathFreeObject(obj);
13730 return(0);
13731 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013732
Daniel Veillardf06307e2001-07-03 10:35:50 +000013733 /*
William M. Brack08171912003-12-29 02:52:11 +000013734 * The result of the evaluation needs to be tested to
13735 * decide whether the filter succeeded or not
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013736 */
13737 /*
13738 * OPTIMIZE TODO: Can we use
13739 * xmlXPathNodeSetAdd*Unique()* instead?
13740 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013741 res = valuePop(ctxt);
13742 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13743 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13744 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013745
Daniel Veillardf06307e2001-07-03 10:35:50 +000013746 /*
13747 * Cleanup
13748 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013749 if (res != NULL) {
13750 xmlXPathReleaseObject(ctxt->context, res);
13751 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013752 if (ctxt->value == tmp) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013753 valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013754 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013755 /*
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013756 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013757 * in order to avoid massive recreation inside this
13758 * loop.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013759 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013760 } else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013761 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013762 ctxt->context->node = NULL;
13763 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013764 if (tmp != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013765 xmlXPathReleaseObject(ctxt->context, tmp);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013766 /*
13767 * The result is used as the new evaluation set.
13768 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013769 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013770 ctxt->context->node = NULL;
13771 ctxt->context->contextSize = -1;
13772 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000013773 /* may want to move this past the '}' later */
13774 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013775 valuePush(ctxt,
13776 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013777 }
13778 ctxt->context->node = oldnode;
13779 return (total);
13780 }
13781 case XPATH_OP_SORT:
13782 if (op->ch1 != -1)
13783 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013784 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013785 if ((ctxt->value != NULL) &&
13786 (ctxt->value->type == XPATH_NODESET) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013787 (ctxt->value->nodesetval != NULL) &&
13788 (ctxt->value->nodesetval->nodeNr > 1))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013789 {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013790 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013791 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013792 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013793#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013794 case XPATH_OP_RANGETO:{
13795 xmlXPathObjectPtr range;
13796 xmlXPathObjectPtr res, obj;
13797 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000013798 xmlLocationSetPtr newlocset = NULL;
13799 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013800 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000013801 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013802
Daniel Veillardf06307e2001-07-03 10:35:50 +000013803 if (op->ch1 != -1)
13804 total +=
13805 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13806 if (op->ch2 == -1)
13807 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013808
William M. Brack08171912003-12-29 02:52:11 +000013809 if (ctxt->value->type == XPATH_LOCATIONSET) {
13810 /*
13811 * Extract the old locset, and then evaluate the result of the
13812 * expression for all the element in the locset. use it to grow
13813 * up a new locset.
13814 */
13815 CHECK_TYPE0(XPATH_LOCATIONSET);
13816 obj = valuePop(ctxt);
13817 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013818
William M. Brack08171912003-12-29 02:52:11 +000013819 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000013820 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000013821 ctxt->context->contextSize = 0;
13822 ctxt->context->proximityPosition = 0;
13823 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13824 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013825 if (res != NULL) {
13826 xmlXPathReleaseObject(ctxt->context, res);
13827 }
William M. Brack08171912003-12-29 02:52:11 +000013828 valuePush(ctxt, obj);
13829 CHECK_ERROR0;
13830 return (total);
13831 }
13832 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013833
William M. Brack08171912003-12-29 02:52:11 +000013834 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013835 /*
William M. Brack08171912003-12-29 02:52:11 +000013836 * Run the evaluation with a node list made of a
13837 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000013838 */
William M. Brackf7eb7942003-12-31 07:59:17 +000013839 ctxt->context->node = oldlocset->locTab[i]->user;
13840 ctxt->context->contextSize = oldlocset->locNr;
13841 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013842 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13843 ctxt->context->node);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013844 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013845
Daniel Veillardf06307e2001-07-03 10:35:50 +000013846 if (op->ch2 != -1)
13847 total +=
13848 xmlXPathCompOpEval(ctxt,
13849 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013850 if (ctxt->error != XPATH_EXPRESSION_OK) {
13851 xmlXPathFreeObject(obj);
13852 return(0);
13853 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013854
Daniel Veillardf06307e2001-07-03 10:35:50 +000013855 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000013856 if (res->type == XPATH_LOCATIONSET) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000013857 xmlLocationSetPtr rloc =
William M. Brack72ee48d2003-12-30 08:30:19 +000013858 (xmlLocationSetPtr)res->user;
13859 for (j=0; j<rloc->locNr; j++) {
13860 range = xmlXPtrNewRange(
13861 oldlocset->locTab[i]->user,
13862 oldlocset->locTab[i]->index,
13863 rloc->locTab[j]->user2,
13864 rloc->locTab[j]->index2);
13865 if (range != NULL) {
13866 xmlXPtrLocationSetAdd(newlocset, range);
13867 }
13868 }
13869 } else {
13870 range = xmlXPtrNewRangeNodeObject(
13871 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13872 if (range != NULL) {
13873 xmlXPtrLocationSetAdd(newlocset,range);
13874 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013875 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013876
Daniel Veillardf06307e2001-07-03 10:35:50 +000013877 /*
13878 * Cleanup
13879 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013880 if (res != NULL) {
13881 xmlXPathReleaseObject(ctxt->context, res);
13882 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013883 if (ctxt->value == tmp) {
13884 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013885 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013886 }
13887
13888 ctxt->context->node = NULL;
13889 }
William M. Brack72ee48d2003-12-30 08:30:19 +000013890 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000013891 CHECK_TYPE0(XPATH_NODESET);
13892 obj = valuePop(ctxt);
13893 oldset = obj->nodesetval;
13894 ctxt->context->node = NULL;
13895
13896 newlocset = xmlXPtrLocationSetCreate(NULL);
13897
13898 if (oldset != NULL) {
13899 for (i = 0; i < oldset->nodeNr; i++) {
13900 /*
13901 * Run the evaluation with a node list made of a single item
13902 * in the nodeset.
13903 */
13904 ctxt->context->node = oldset->nodeTab[i];
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013905 /*
13906 * OPTIMIZE TODO: Avoid recreation for every iteration.
13907 */
13908 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13909 ctxt->context->node);
William M. Brack08171912003-12-29 02:52:11 +000013910 valuePush(ctxt, tmp);
13911
13912 if (op->ch2 != -1)
13913 total +=
13914 xmlXPathCompOpEval(ctxt,
13915 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013916 if (ctxt->error != XPATH_EXPRESSION_OK) {
13917 xmlXPathFreeObject(obj);
13918 return(0);
13919 }
William M. Brack08171912003-12-29 02:52:11 +000013920
William M. Brack08171912003-12-29 02:52:11 +000013921 res = valuePop(ctxt);
13922 range =
13923 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13924 res);
13925 if (range != NULL) {
13926 xmlXPtrLocationSetAdd(newlocset, range);
13927 }
13928
13929 /*
13930 * Cleanup
13931 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013932 if (res != NULL) {
13933 xmlXPathReleaseObject(ctxt->context, res);
13934 }
William M. Brack08171912003-12-29 02:52:11 +000013935 if (ctxt->value == tmp) {
13936 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013937 xmlXPathReleaseObject(ctxt->context, res);
William M. Brack08171912003-12-29 02:52:11 +000013938 }
13939
13940 ctxt->context->node = NULL;
13941 }
13942 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013943 }
13944
13945 /*
13946 * The result is used as the new evaluation set.
13947 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013948 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013949 ctxt->context->node = NULL;
13950 ctxt->context->contextSize = -1;
13951 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000013952 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013953 return (total);
13954 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013955#endif /* LIBXML_XPTR_ENABLED */
13956 }
13957 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000013958 "XPath: unknown precompiled operation %d\n", op->op);
13959 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013960}
13961
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013962/**
13963 * xmlXPathCompOpEvalToBoolean:
13964 * @ctxt: the XPath parser context
13965 *
13966 * Evaluates if the expression evaluates to true.
13967 *
13968 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13969 */
13970static int
13971xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013972 xmlXPathStepOpPtr op,
13973 int isPredicate)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013974{
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013975 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013976
13977start:
13978 /* comp = ctxt->comp; */
13979 switch (op->op) {
13980 case XPATH_OP_END:
13981 return (0);
13982 case XPATH_OP_VALUE:
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013983 resObj = (xmlXPathObjectPtr) op->value4;
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000013984 if (isPredicate)
13985 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13986 return(xmlXPathCastToBoolean(resObj));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013987 case XPATH_OP_SORT:
13988 /*
13989 * We don't need sorting for boolean results. Skip this one.
13990 */
13991 if (op->ch1 != -1) {
13992 op = &ctxt->comp->steps[op->ch1];
13993 goto start;
13994 }
13995 return(0);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013996 case XPATH_OP_COLLECT:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013997 if (op->ch1 == -1)
13998 return(0);
13999
14000 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14001 if (ctxt->error != XPATH_EXPRESSION_OK)
14002 return(-1);
14003
14004 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14005 if (ctxt->error != XPATH_EXPRESSION_OK)
14006 return(-1);
14007
14008 resObj = valuePop(ctxt);
14009 if (resObj == NULL)
14010 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014011 break;
14012 default:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014013 /*
14014 * Fallback to call xmlXPathCompOpEval().
14015 */
14016 xmlXPathCompOpEval(ctxt, op);
14017 if (ctxt->error != XPATH_EXPRESSION_OK)
14018 return(-1);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014019
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014020 resObj = valuePop(ctxt);
14021 if (resObj == NULL)
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000014022 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014023 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014024 }
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014025
14026 if (resObj) {
14027 int res;
14028
14029 if (resObj->type == XPATH_BOOLEAN) {
14030 res = resObj->boolval;
14031 } else if (isPredicate) {
14032 /*
14033 * For predicates a result of type "number" is handled
14034 * differently:
14035 * SPEC XPath 1.0:
14036 * "If the result is a number, the result will be converted
14037 * to true if the number is equal to the context position
14038 * and will be converted to false otherwise;"
14039 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000014040 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014041 } else {
14042 res = xmlXPathCastToBoolean(resObj);
14043 }
14044 xmlXPathReleaseObject(ctxt->context, resObj);
14045 return(res);
14046 }
14047
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014048 return(0);
14049}
14050
Daniel Veillard56de87e2005-02-16 00:22:29 +000014051#ifdef XPATH_STREAMING
14052/**
14053 * xmlXPathRunStreamEval:
14054 * @ctxt: the XPath parser context with the compiled expression
14055 *
14056 * Evaluate the Precompiled Streamable XPath expression in the given context.
14057 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014058static int
14059xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14060 xmlXPathObjectPtr *resultSeq, int toBool)
14061{
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014062 int max_depth, min_depth;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014063 int from_root;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014064 int ret, depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014065 int eval_all_nodes;
William M. Brack12d37ab2005-02-21 13:54:07 +000014066 xmlNodePtr cur = NULL, limit = NULL;
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014067 xmlStreamCtxtPtr patstream = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014068
14069 int nb_nodes = 0;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014070
14071 if ((ctxt == NULL) || (comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014072 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014073 max_depth = xmlPatternMaxDepth(comp);
14074 if (max_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014075 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014076 if (max_depth == -2)
14077 max_depth = 10000;
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014078 min_depth = xmlPatternMinDepth(comp);
14079 if (min_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014080 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014081 from_root = xmlPatternFromRoot(comp);
14082 if (from_root < 0)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014083 return(-1);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014084#if 0
14085 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14086#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000014087
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014088 if (! toBool) {
14089 if (resultSeq == NULL)
14090 return(-1);
14091 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14092 if (*resultSeq == NULL)
14093 return(-1);
14094 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014095
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014096 /*
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014097 * handle the special cases of "/" amd "." being matched
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014098 */
14099 if (min_depth == 0) {
14100 if (from_root) {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014101 /* Select "/" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014102 if (toBool)
14103 return(1);
14104 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14105 (xmlNodePtr) ctxt->doc);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014106 } else {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014107 /* Select "self::node()" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014108 if (toBool)
14109 return(1);
14110 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014111 }
14112 }
14113 if (max_depth == 0) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014114 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014115 }
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014116
Daniel Veillard56de87e2005-02-16 00:22:29 +000014117 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000014118 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014119 } else if (ctxt->node != NULL) {
14120 switch (ctxt->node->type) {
14121 case XML_ELEMENT_NODE:
14122 case XML_DOCUMENT_NODE:
14123 case XML_DOCUMENT_FRAG_NODE:
14124 case XML_HTML_DOCUMENT_NODE:
14125#ifdef LIBXML_DOCB_ENABLED
14126 case XML_DOCB_DOCUMENT_NODE:
14127#endif
14128 cur = ctxt->node;
14129 break;
14130 case XML_ATTRIBUTE_NODE:
14131 case XML_TEXT_NODE:
14132 case XML_CDATA_SECTION_NODE:
14133 case XML_ENTITY_REF_NODE:
14134 case XML_ENTITY_NODE:
14135 case XML_PI_NODE:
14136 case XML_COMMENT_NODE:
14137 case XML_NOTATION_NODE:
14138 case XML_DTD_NODE:
14139 case XML_DOCUMENT_TYPE_NODE:
14140 case XML_ELEMENT_DECL:
14141 case XML_ATTRIBUTE_DECL:
14142 case XML_ENTITY_DECL:
14143 case XML_NAMESPACE_DECL:
14144 case XML_XINCLUDE_START:
14145 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000014146 break;
14147 }
14148 limit = cur;
14149 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014150 if (cur == NULL) {
14151 return(0);
14152 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014153
14154 patstream = xmlPatternGetStreamCtxt(comp);
14155 if (patstream == NULL) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014156 /*
14157 * QUESTION TODO: Is this an error?
14158 */
14159 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014160 }
14161
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014162 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014163
Daniel Veillard56de87e2005-02-16 00:22:29 +000014164 if (from_root) {
14165 ret = xmlStreamPush(patstream, NULL, NULL);
14166 if (ret < 0) {
14167 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014168 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014169 goto return_1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014170 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014171 }
14172 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014173 depth = 0;
14174 goto scan_children;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014175next_node:
Daniel Veillardd3ff7ef2006-02-27 19:43:17 +000014176 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014177 nb_nodes++;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014178
14179 switch (cur->type) {
14180 case XML_ELEMENT_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014181 case XML_TEXT_NODE:
14182 case XML_CDATA_SECTION_NODE:
14183 case XML_COMMENT_NODE:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014184 case XML_PI_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014185 if (cur->type == XML_ELEMENT_NODE) {
14186 ret = xmlStreamPush(patstream, cur->name,
Daniel Veillard56de87e2005-02-16 00:22:29 +000014187 (cur->ns ? cur->ns->href : NULL));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014188 } else if (eval_all_nodes)
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014189 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14190 else
14191 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014192
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014193 if (ret < 0) {
14194 /* NOP. */
14195 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014196 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014197 goto return_1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014198 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014199 }
14200 if ((cur->children == NULL) || (depth >= max_depth)) {
14201 ret = xmlStreamPop(patstream);
14202 while (cur->next != NULL) {
14203 cur = cur->next;
14204 if ((cur->type != XML_ENTITY_DECL) &&
14205 (cur->type != XML_DTD_NODE))
14206 goto next_node;
14207 }
14208 }
14209 default:
14210 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014211 }
14212
Daniel Veillard56de87e2005-02-16 00:22:29 +000014213scan_children:
14214 if ((cur->children != NULL) && (depth < max_depth)) {
14215 /*
Daniel Veillard45490ae2008-07-29 09:13:19 +000014216 * Do not descend on entities declarations
Daniel Veillard56de87e2005-02-16 00:22:29 +000014217 */
14218 if (cur->children->type != XML_ENTITY_DECL) {
14219 cur = cur->children;
14220 depth++;
14221 /*
14222 * Skip DTDs
14223 */
14224 if (cur->type != XML_DTD_NODE)
14225 continue;
14226 }
14227 }
14228
14229 if (cur == limit)
14230 break;
14231
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 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014238
Daniel Veillard56de87e2005-02-16 00:22:29 +000014239 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014240 cur = cur->parent;
14241 depth--;
14242 if ((cur == NULL) || (cur == limit))
14243 goto done;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014244 if (cur->type == XML_ELEMENT_NODE) {
14245 ret = xmlStreamPop(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014246 } else if ((eval_all_nodes) &&
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014247 ((cur->type == XML_TEXT_NODE) ||
14248 (cur->type == XML_CDATA_SECTION_NODE) ||
14249 (cur->type == XML_COMMENT_NODE) ||
14250 (cur->type == XML_PI_NODE)))
14251 {
14252 ret = xmlStreamPop(patstream);
14253 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014254 if (cur->next != NULL) {
14255 cur = cur->next;
14256 break;
14257 }
14258 } while (cur != NULL);
14259
14260 } while ((cur != NULL) && (depth >= 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014261
Daniel Veillard56de87e2005-02-16 00:22:29 +000014262done:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014263
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014264#if 0
14265 printf("stream eval: checked %d nodes selected %d\n",
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014266 nb_nodes, retObj->nodesetval->nodeNr);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014267#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014268
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014269 if (patstream)
14270 xmlFreeStreamCtxt(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014271 return(0);
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014272
14273return_1:
14274 if (patstream)
14275 xmlFreeStreamCtxt(patstream);
14276 return(1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014277}
14278#endif /* XPATH_STREAMING */
14279
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014280/**
14281 * xmlXPathRunEval:
14282 * @ctxt: the XPath parser context with the compiled expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014283 * @toBool: evaluate to a boolean result
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014284 *
14285 * Evaluate the Precompiled XPath expression in the given context.
14286 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014287static int
14288xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14289{
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014290 xmlXPathCompExprPtr comp;
14291
14292 if ((ctxt == NULL) || (ctxt->comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014293 return(-1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014294
14295 if (ctxt->valueTab == NULL) {
14296 /* Allocate the value stack */
Daniel Veillard45490ae2008-07-29 09:13:19 +000014297 ctxt->valueTab = (xmlXPathObjectPtr *)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014298 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14299 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000014300 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014301 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014302 }
14303 ctxt->valueNr = 0;
14304 ctxt->valueMax = 10;
14305 ctxt->value = NULL;
14306 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014307#ifdef XPATH_STREAMING
14308 if (ctxt->comp->stream) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014309 int res;
14310
14311 if (toBool) {
14312 /*
14313 * Evaluation to boolean result.
14314 */
14315 res = xmlXPathRunStreamEval(ctxt->context,
14316 ctxt->comp->stream, NULL, 1);
14317 if (res != -1)
14318 return(res);
14319 } else {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014320 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014321
14322 /*
14323 * Evaluation to a sequence.
14324 */
14325 res = xmlXPathRunStreamEval(ctxt->context,
14326 ctxt->comp->stream, &resObj, 0);
14327
14328 if ((res != -1) && (resObj != NULL)) {
14329 valuePush(ctxt, resObj);
14330 return(0);
14331 }
14332 if (resObj != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +000014333 xmlXPathReleaseObject(ctxt->context, resObj);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014334 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014335 /*
14336 * QUESTION TODO: This falls back to normal XPath evaluation
14337 * if res == -1. Is this intended?
14338 */
Daniel Veillard56de87e2005-02-16 00:22:29 +000014339 }
14340#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014341 comp = ctxt->comp;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014342 if (comp->last < 0) {
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014343 xmlGenericError(xmlGenericErrorContext,
14344 "xmlXPathRunEval: last is less than zero\n");
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014345 return(-1);
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014346 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014347 if (toBool)
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014348 return(xmlXPathCompOpEvalToBoolean(ctxt,
14349 &comp->steps[comp->last], 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014350 else
14351 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14352
14353 return(0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014354}
14355
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014356/************************************************************************
14357 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +000014358 * Public interfaces *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014359 * *
14360 ************************************************************************/
14361
14362/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014363 * xmlXPathEvalPredicate:
14364 * @ctxt: the XPath context
14365 * @res: the Predicate Expression evaluation result
14366 *
14367 * Evaluate a predicate result for the current node.
14368 * A PredicateExpr is evaluated by evaluating the Expr and converting
14369 * the result to a boolean. If the result is a number, the result will
14370 * be converted to true if the number is equal to the position of the
14371 * context node in the context node list (as returned by the position
14372 * function) and will be converted to false otherwise; if the result
14373 * is not a number, then the result will be converted as if by a call
Daniel Veillard45490ae2008-07-29 09:13:19 +000014374 * to the boolean function.
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014375 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014376 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014377 */
14378int
14379xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014380 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014381 switch (res->type) {
14382 case XPATH_BOOLEAN:
14383 return(res->boolval);
14384 case XPATH_NUMBER:
14385 return(res->floatval == ctxt->proximityPosition);
14386 case XPATH_NODESET:
14387 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000014388 if (res->nodesetval == NULL)
14389 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014390 return(res->nodesetval->nodeNr != 0);
14391 case XPATH_STRING:
14392 return((res->stringval != NULL) &&
14393 (xmlStrlen(res->stringval) != 0));
14394 default:
14395 STRANGE
14396 }
14397 return(0);
14398}
14399
14400/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014401 * xmlXPathEvaluatePredicateResult:
14402 * @ctxt: the XPath Parser context
14403 * @res: the Predicate Expression evaluation result
14404 *
14405 * Evaluate a predicate result for the current node.
14406 * A PredicateExpr is evaluated by evaluating the Expr and converting
14407 * the result to a boolean. If the result is a number, the result will
14408 * be converted to true if the number is equal to the position of the
14409 * context node in the context node list (as returned by the position
14410 * function) and will be converted to false otherwise; if the result
14411 * is not a number, then the result will be converted as if by a call
Daniel Veillard45490ae2008-07-29 09:13:19 +000014412 * to the boolean function.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014413 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014414 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014415 */
14416int
Daniel Veillard45490ae2008-07-29 09:13:19 +000014417xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014418 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014419 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014420 switch (res->type) {
14421 case XPATH_BOOLEAN:
14422 return(res->boolval);
14423 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000014424#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000014425 return((res->floatval == ctxt->context->proximityPosition) &&
14426 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000014427#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014428 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000014429#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014430 case XPATH_NODESET:
14431 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000014432 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000014433 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014434 return(res->nodesetval->nodeNr != 0);
14435 case XPATH_STRING:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014436 return((res->stringval != NULL) && (res->stringval[0] != 0));
William M. Brack08171912003-12-29 02:52:11 +000014437#ifdef LIBXML_XPTR_ENABLED
14438 case XPATH_LOCATIONSET:{
14439 xmlLocationSetPtr ptr = res->user;
14440 if (ptr == NULL)
14441 return(0);
14442 return (ptr->locNr != 0);
14443 }
14444#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014445 default:
14446 STRANGE
14447 }
14448 return(0);
14449}
14450
Daniel Veillard56de87e2005-02-16 00:22:29 +000014451#ifdef XPATH_STREAMING
14452/**
14453 * xmlXPathTryStreamCompile:
14454 * @ctxt: an XPath context
14455 * @str: the XPath expression
14456 *
14457 * Try to compile the XPath expression as a streamable subset.
14458 *
14459 * Returns the compiled expression or NULL if failed to compile.
14460 */
14461static xmlXPathCompExprPtr
14462xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14463 /*
14464 * Optimization: use streaming patterns when the XPath expression can
14465 * be compiled to a stream lookup
14466 */
14467 xmlPatternPtr stream;
14468 xmlXPathCompExprPtr comp;
14469 xmlDictPtr dict = NULL;
14470 const xmlChar **namespaces = NULL;
14471 xmlNsPtr ns;
14472 int i, j;
14473
14474 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14475 (!xmlStrchr(str, '@'))) {
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014476 const xmlChar *tmp;
14477
14478 /*
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014479 * We don't try to handle expressions using the verbose axis
14480 * specifiers ("::"), just the simplied form at this point.
14481 * Additionally, if there is no list of namespaces available and
14482 * there's a ":" in the expression, indicating a prefixed QName,
14483 * then we won't try to compile either. xmlPatterncompile() needs
14484 * to have a list of namespaces at compilation time in order to
14485 * compile prefixed name tests.
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014486 */
14487 tmp = xmlStrchr(str, ':');
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014488 if ((tmp != NULL) &&
14489 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
Daniel Veillard45490ae2008-07-29 09:13:19 +000014490 return(NULL);
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014491
Daniel Veillard56de87e2005-02-16 00:22:29 +000014492 if (ctxt != NULL) {
14493 dict = ctxt->dict;
14494 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000014495 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000014496 if (namespaces == NULL) {
14497 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14498 return(NULL);
14499 }
14500 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14501 ns = ctxt->namespaces[j];
14502 namespaces[i++] = ns->href;
14503 namespaces[i++] = ns->prefix;
14504 }
14505 namespaces[i++] = NULL;
14506 namespaces[i++] = NULL;
14507 }
14508 }
14509
William M. Brackea152c02005-06-09 18:12:28 +000014510 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14511 &namespaces[0]);
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014512 if (namespaces != NULL) {
14513 xmlFree((xmlChar **)namespaces);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014514 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014515 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14516 comp = xmlXPathNewCompExpr();
14517 if (comp == NULL) {
14518 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14519 return(NULL);
14520 }
14521 comp->stream = stream;
14522 comp->dict = dict;
14523 if (comp->dict)
14524 xmlDictReference(comp->dict);
14525 return(comp);
14526 }
14527 xmlFreePattern(stream);
14528 }
14529 return(NULL);
14530}
14531#endif /* XPATH_STREAMING */
14532
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014533static int
14534xmlXPathCanRewriteDosExpression(xmlChar *expr)
14535{
14536 if (expr == NULL)
14537 return(0);
14538 do {
14539 if ((*expr == '/') && (*(++expr) == '/'))
14540 return(1);
14541 } while (*expr++);
14542 return(0);
14543}
14544static void
14545xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14546{
14547 /*
14548 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14549 * internal representation.
14550 */
14551 if (op->ch1 != -1) {
14552 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +000014553 ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014554 ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
14555 ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
14556 {
14557 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014558 * This is a "child::foo"
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014559 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000014560 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014561
14562 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +000014563 (prevop->ch1 != -1) &&
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014564 ((xmlXPathAxisVal) prevop->value ==
14565 AXIS_DESCENDANT_OR_SELF) &&
14566 (prevop->ch2 == -1) &&
14567 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014568 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
14569 (comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
Daniel Veillard45490ae2008-07-29 09:13:19 +000014570 {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014571 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014572 * This is a "/descendant-or-self::node()" without predicates.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014573 * Eliminate it.
14574 */
14575 op->ch1 = prevop->ch1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014576 op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014577 }
14578 }
14579 if (op->ch1 != -1)
14580 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
14581 }
14582 if (op->ch2 != -1)
14583 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
14584}
14585
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014586/**
Daniel Veillard4773df22004-01-23 13:15:13 +000014587 * xmlXPathCtxtCompile:
14588 * @ctxt: an XPath context
14589 * @str: the XPath expression
14590 *
14591 * Compile an XPath expression
14592 *
14593 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14594 * the caller has to free the object.
14595 */
14596xmlXPathCompExprPtr
14597xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14598 xmlXPathParserContextPtr pctxt;
14599 xmlXPathCompExprPtr comp;
14600
Daniel Veillard56de87e2005-02-16 00:22:29 +000014601#ifdef XPATH_STREAMING
14602 comp = xmlXPathTryStreamCompile(ctxt, str);
14603 if (comp != NULL)
14604 return(comp);
14605#endif
14606
Daniel Veillard4773df22004-01-23 13:15:13 +000014607 xmlXPathInit();
14608
14609 pctxt = xmlXPathNewParserContext(str, ctxt);
William M. Brack11be2d02007-01-24 19:17:19 +000014610 if (pctxt == NULL)
14611 return NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014612 xmlXPathCompileExpr(pctxt, 1);
Daniel Veillard4773df22004-01-23 13:15:13 +000014613
14614 if( pctxt->error != XPATH_EXPRESSION_OK )
14615 {
14616 xmlXPathFreeParserContext(pctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000014617 return(NULL);
Daniel Veillard4773df22004-01-23 13:15:13 +000014618 }
14619
14620 if (*pctxt->cur != 0) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014621 /*
Daniel Veillard4773df22004-01-23 13:15:13 +000014622 * aleksey: in some cases this line prints *second* error message
14623 * (see bug #78858) and probably this should be fixed.
14624 * However, we are not sure that all error messages are printed
14625 * out in other places. It's not critical so we leave it as-is for now
14626 */
14627 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14628 comp = NULL;
14629 } else {
14630 comp = pctxt->comp;
14631 pctxt->comp = NULL;
14632 }
14633 xmlXPathFreeParserContext(pctxt);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014634
Daniel Veillard4773df22004-01-23 13:15:13 +000014635 if (comp != NULL) {
14636 comp->expr = xmlStrdup(str);
14637#ifdef DEBUG_EVAL_COUNTS
14638 comp->string = xmlStrdup(str);
14639 comp->nb = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014640#endif
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014641 if ((comp->expr != NULL) &&
14642 (comp->nbStep > 2) &&
14643 (comp->last >= 0) &&
Kasimier T. Buchcik7cb3fa92006-06-06 15:27:46 +000014644 (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
14645 {
14646 xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014647 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014648 }
Daniel Veillard4773df22004-01-23 13:15:13 +000014649 return(comp);
14650}
14651
14652/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014653 * xmlXPathCompile:
14654 * @str: the XPath expression
14655 *
14656 * Compile an XPath expression
14657 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000014658 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014659 * the caller has to free the object.
14660 */
14661xmlXPathCompExprPtr
14662xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000014663 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014664}
14665
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014666/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014667 * xmlXPathCompiledEvalInternal:
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014668 * @comp: the compiled XPath expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014669 * @ctxt: the XPath context
14670 * @resObj: the resulting XPath object or NULL
14671 * @toBool: 1 if only a boolean result is requested
Owen Taylor3473f882001-02-23 17:55:21 +000014672 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014673 * Evaluate the Precompiled XPath expression in the given context.
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014674 * The caller has to free @resObj.
Owen Taylor3473f882001-02-23 17:55:21 +000014675 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014676 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000014677 * the caller has to free the object.
14678 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014679static int
14680xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14681 xmlXPathContextPtr ctxt,
14682 xmlXPathObjectPtr *resObj,
14683 int toBool)
14684{
Daniel Veillard45490ae2008-07-29 09:13:19 +000014685 xmlXPathParserContextPtr pctxt;
Daniel Veillard81463942001-10-16 12:34:39 +000014686#ifndef LIBXML_THREAD_ENABLED
14687 static int reentance = 0;
14688#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014689 int res;
Owen Taylor3473f882001-02-23 17:55:21 +000014690
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014691 CHECK_CTXT_NEG(ctxt)
William M. Brackf13f77f2004-11-12 16:03:48 +000014692
14693 if (comp == NULL)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014694 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +000014695 xmlXPathInit();
14696
Daniel Veillard81463942001-10-16 12:34:39 +000014697#ifndef LIBXML_THREAD_ENABLED
14698 reentance++;
14699 if (reentance > 1)
14700 xmlXPathDisableOptimizer = 1;
14701#endif
14702
Daniel Veillardf06307e2001-07-03 10:35:50 +000014703#ifdef DEBUG_EVAL_COUNTS
14704 comp->nb++;
14705 if ((comp->string != NULL) && (comp->nb > 100)) {
14706 fprintf(stderr, "100 x %s\n", comp->string);
14707 comp->nb = 0;
14708 }
14709#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014710 pctxt = xmlXPathCompParserContext(comp, ctxt);
14711 res = xmlXPathRunEval(pctxt, toBool);
Owen Taylor3473f882001-02-23 17:55:21 +000014712
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014713 if (resObj) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014714 if (pctxt->value == NULL) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014715 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014716 "xmlXPathCompiledEval: evaluation failed\n");
Daniel Veillard45490ae2008-07-29 09:13:19 +000014717 *resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014718 } else {
14719 *resObj = valuePop(pctxt);
14720 }
Owen Taylor3473f882001-02-23 17:55:21 +000014721 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014722
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014723 /*
14724 * Pop all remaining objects from the stack.
14725 */
14726 if (pctxt->valueNr > 0) {
14727 xmlXPathObjectPtr tmp;
14728 int stack = 0;
14729
14730 do {
14731 tmp = valuePop(pctxt);
14732 if (tmp != NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014733 stack++;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014734 xmlXPathReleaseObject(ctxt, tmp);
14735 }
14736 } while (tmp != NULL);
14737 if ((stack != 0) &&
14738 ((toBool) || ((resObj) && (*resObj))))
14739 {
14740 xmlGenericError(xmlGenericErrorContext,
14741 "xmlXPathCompiledEval: %d objects left on the stack.\n",
14742 stack);
14743 }
Owen Taylor3473f882001-02-23 17:55:21 +000014744 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014745
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014746 if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14747 xmlXPathFreeObject(*resObj);
14748 *resObj = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014749 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014750 pctxt->comp = NULL;
14751 xmlXPathFreeParserContext(pctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000014752#ifndef LIBXML_THREAD_ENABLED
14753 reentance--;
14754#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014755
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014756 return(res);
14757}
14758
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014759/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014760 * xmlXPathCompiledEval:
14761 * @comp: the compiled XPath expression
14762 * @ctx: the XPath context
14763 *
14764 * Evaluate the Precompiled XPath expression in the given context.
14765 *
14766 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14767 * the caller has to free the object.
14768 */
14769xmlXPathObjectPtr
14770xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14771{
14772 xmlXPathObjectPtr res = NULL;
14773
14774 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14775 return(res);
14776}
14777
14778/**
14779 * xmlXPathCompiledEvalToBoolean:
14780 * @comp: the compiled XPath expression
14781 * @ctxt: the XPath context
14782 *
14783 * Applies the XPath boolean() function on the result of the given
14784 * compiled expression.
14785 *
14786 * Returns 1 if the expression evaluated to true, 0 if to false and
14787 * -1 in API and internal errors.
14788 */
14789int
14790xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14791 xmlXPathContextPtr ctxt)
14792{
14793 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14794}
14795
14796/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014797 * xmlXPathEvalExpr:
14798 * @ctxt: the XPath Parser context
14799 *
14800 * Parse and evaluate an XPath expression in the given context,
14801 * then push the result on the context stack
14802 */
14803void
14804xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014805#ifdef XPATH_STREAMING
14806 xmlXPathCompExprPtr comp;
14807#endif
14808
Daniel Veillarda82b1822004-11-08 16:24:57 +000014809 if (ctxt == NULL) return;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014810
Daniel Veillard56de87e2005-02-16 00:22:29 +000014811#ifdef XPATH_STREAMING
14812 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14813 if (comp != NULL) {
14814 if (ctxt->comp != NULL)
14815 xmlXPathFreeCompExpr(ctxt->comp);
14816 ctxt->comp = comp;
14817 if (ctxt->cur != NULL)
14818 while (*ctxt->cur != 0) ctxt->cur++;
14819 } else
14820#endif
14821 {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014822 xmlXPathCompileExpr(ctxt, 1);
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014823 /*
14824 * In this scenario the expression string will sit in ctxt->base.
14825 */
14826 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
14827 (ctxt->comp != NULL) &&
14828 (ctxt->base != NULL) &&
Kasimier T. Buchcik7cb3fa92006-06-06 15:27:46 +000014829 (ctxt->comp->nbStep > 2) &&
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014830 (ctxt->comp->last >= 0) &&
14831 (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014832 {
14833 xmlXPathRewriteDOSExpression(ctxt->comp,
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014834 &ctxt->comp->steps[ctxt->comp->last]);
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014835 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014836 }
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000014837 CHECK_ERROR;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014838 xmlXPathRunEval(ctxt, 0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014839}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014840
14841/**
14842 * xmlXPathEval:
14843 * @str: the XPath expression
14844 * @ctx: the XPath context
14845 *
14846 * Evaluate the XPath Location Path in the given context.
14847 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014848 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014849 * the caller has to free the object.
14850 */
14851xmlXPathObjectPtr
14852xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14853 xmlXPathParserContextPtr ctxt;
14854 xmlXPathObjectPtr res, tmp, init = NULL;
14855 int stack = 0;
14856
William M. Brackf13f77f2004-11-12 16:03:48 +000014857 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014858
William M. Brackf13f77f2004-11-12 16:03:48 +000014859 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014860
14861 ctxt = xmlXPathNewParserContext(str, ctx);
William M. Brack11be2d02007-01-24 19:17:19 +000014862 if (ctxt == NULL)
14863 return NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014864 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014865
14866 if (ctxt->value == NULL) {
14867 xmlGenericError(xmlGenericErrorContext,
14868 "xmlXPathEval: evaluation failed\n");
14869 res = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014870 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
Daniel Veillard56de87e2005-02-16 00:22:29 +000014871#ifdef XPATH_STREAMING
14872 && (ctxt->comp->stream == NULL)
14873#endif
14874 ) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014875 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14876 res = NULL;
14877 } else {
14878 res = valuePop(ctxt);
14879 }
14880
14881 do {
14882 tmp = valuePop(ctxt);
14883 if (tmp != NULL) {
14884 if (tmp != init)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014885 stack++;
14886 xmlXPathReleaseObject(ctx, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014887 }
14888 } while (tmp != NULL);
14889 if ((stack != 0) && (res != NULL)) {
14890 xmlGenericError(xmlGenericErrorContext,
14891 "xmlXPathEval: %d object left on the stack\n",
14892 stack);
14893 }
14894 if (ctxt->error != XPATH_EXPRESSION_OK) {
14895 xmlXPathFreeObject(res);
14896 res = NULL;
14897 }
14898
Owen Taylor3473f882001-02-23 17:55:21 +000014899 xmlXPathFreeParserContext(ctxt);
14900 return(res);
14901}
14902
14903/**
14904 * xmlXPathEvalExpression:
14905 * @str: the XPath expression
14906 * @ctxt: the XPath context
14907 *
14908 * Evaluate the XPath expression in the given context.
14909 *
14910 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14911 * the caller has to free the object.
14912 */
14913xmlXPathObjectPtr
14914xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14915 xmlXPathParserContextPtr pctxt;
14916 xmlXPathObjectPtr res, tmp;
14917 int stack = 0;
14918
William M. Brackf13f77f2004-11-12 16:03:48 +000014919 CHECK_CTXT(ctxt)
Owen Taylor3473f882001-02-23 17:55:21 +000014920
William M. Brackf13f77f2004-11-12 16:03:48 +000014921 xmlXPathInit();
Owen Taylor3473f882001-02-23 17:55:21 +000014922
14923 pctxt = xmlXPathNewParserContext(str, ctxt);
William M. Brack11be2d02007-01-24 19:17:19 +000014924 if (pctxt == NULL)
14925 return NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000014926 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000014927
Daniel Veillardc465ffc2006-10-17 19:39:33 +000014928 if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
Owen Taylor3473f882001-02-23 17:55:21 +000014929 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14930 res = NULL;
14931 } else {
14932 res = valuePop(pctxt);
14933 }
14934 do {
14935 tmp = valuePop(pctxt);
14936 if (tmp != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014937 xmlXPathReleaseObject(ctxt, tmp);
Owen Taylor3473f882001-02-23 17:55:21 +000014938 stack++;
14939 }
14940 } while (tmp != NULL);
14941 if ((stack != 0) && (res != NULL)) {
14942 xmlGenericError(xmlGenericErrorContext,
14943 "xmlXPathEvalExpression: %d object left on the stack\n",
14944 stack);
14945 }
14946 xmlXPathFreeParserContext(pctxt);
14947 return(res);
14948}
14949
Daniel Veillard42766c02002-08-22 20:52:17 +000014950/************************************************************************
14951 * *
14952 * Extra functions not pertaining to the XPath spec *
14953 * *
14954 ************************************************************************/
14955/**
14956 * xmlXPathEscapeUriFunction:
14957 * @ctxt: the XPath Parser context
14958 * @nargs: the number of arguments
14959 *
14960 * Implement the escape-uri() XPath function
14961 * string escape-uri(string $str, bool $escape-reserved)
14962 *
14963 * This function applies the URI escaping rules defined in section 2 of [RFC
14964 * 2396] to the string supplied as $uri-part, which typically represents all
14965 * or part of a URI. The effect of the function is to replace any special
14966 * character in the string by an escape sequence of the form %xx%yy...,
14967 * where xxyy... is the hexadecimal representation of the octets used to
14968 * represent the character in UTF-8.
14969 *
14970 * The set of characters that are escaped depends on the setting of the
14971 * boolean argument $escape-reserved.
14972 *
14973 * If $escape-reserved is true, all characters are escaped other than lower
14974 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14975 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14976 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14977 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14978 * A-F).
14979 *
14980 * If $escape-reserved is false, the behavior differs in that characters
14981 * referred to in [RFC 2396] as reserved characters are not escaped. These
14982 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
Daniel Veillard45490ae2008-07-29 09:13:19 +000014983 *
Daniel Veillard42766c02002-08-22 20:52:17 +000014984 * [RFC 2396] does not define whether escaped URIs should use lower case or
14985 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14986 * compared using string comparison functions, this function must always use
14987 * the upper-case letters A-F.
Daniel Veillard45490ae2008-07-29 09:13:19 +000014988 *
Daniel Veillard42766c02002-08-22 20:52:17 +000014989 * Generally, $escape-reserved should be set to true when escaping a string
14990 * that is to form a single part of a URI, and to false when escaping an
14991 * entire URI or URI reference.
Daniel Veillard45490ae2008-07-29 09:13:19 +000014992 *
14993 * In the case of non-ascii characters, the string is encoded according to
Daniel Veillard42766c02002-08-22 20:52:17 +000014994 * utf-8 and then converted according to RFC 2396.
14995 *
14996 * Examples
Daniel Veillard45490ae2008-07-29 09:13:19 +000014997 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
Daniel Veillard42766c02002-08-22 20:52:17 +000014998 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14999 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15000 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15001 *
15002 */
Daniel Veillard118aed72002-09-24 14:13:13 +000015003static void
Daniel Veillard42766c02002-08-22 20:52:17 +000015004xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15005 xmlXPathObjectPtr str;
15006 int escape_reserved;
15007 xmlBufferPtr target;
15008 xmlChar *cptr;
15009 xmlChar escape[4];
Daniel Veillard45490ae2008-07-29 09:13:19 +000015010
Daniel Veillard42766c02002-08-22 20:52:17 +000015011 CHECK_ARITY(2);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015012
Daniel Veillard42766c02002-08-22 20:52:17 +000015013 escape_reserved = xmlXPathPopBoolean(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015014
Daniel Veillard42766c02002-08-22 20:52:17 +000015015 CAST_TO_STRING;
15016 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015017
Daniel Veillard42766c02002-08-22 20:52:17 +000015018 target = xmlBufferCreate();
Daniel Veillard45490ae2008-07-29 09:13:19 +000015019
Daniel Veillard42766c02002-08-22 20:52:17 +000015020 escape[0] = '%';
15021 escape[3] = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000015022
Daniel Veillard42766c02002-08-22 20:52:17 +000015023 if (target) {
15024 for (cptr = str->stringval; *cptr; cptr++) {
15025 if ((*cptr >= 'A' && *cptr <= 'Z') ||
15026 (*cptr >= 'a' && *cptr <= 'z') ||
15027 (*cptr >= '0' && *cptr <= '9') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000015028 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
Daniel Veillard42766c02002-08-22 20:52:17 +000015029 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
15030 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000015031 (*cptr == '%' &&
Daniel Veillard42766c02002-08-22 20:52:17 +000015032 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15033 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15034 (cptr[1] >= '0' && cptr[1] <= '9')) &&
15035 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15036 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15037 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15038 (!escape_reserved &&
15039 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15040 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15041 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15042 *cptr == ','))) {
15043 xmlBufferAdd(target, cptr, 1);
15044 } else {
15045 if ((*cptr >> 4) < 10)
15046 escape[1] = '0' + (*cptr >> 4);
15047 else
15048 escape[1] = 'A' - 10 + (*cptr >> 4);
15049 if ((*cptr & 0xF) < 10)
15050 escape[2] = '0' + (*cptr & 0xF);
15051 else
15052 escape[2] = 'A' - 10 + (*cptr & 0xF);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015053
Daniel Veillard42766c02002-08-22 20:52:17 +000015054 xmlBufferAdd(target, &escape[0], 3);
15055 }
15056 }
15057 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015058 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15059 xmlBufferContent(target)));
Daniel Veillard42766c02002-08-22 20:52:17 +000015060 xmlBufferFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015061 xmlXPathReleaseObject(ctxt->context, str);
Daniel Veillard42766c02002-08-22 20:52:17 +000015062}
15063
Owen Taylor3473f882001-02-23 17:55:21 +000015064/**
15065 * xmlXPathRegisterAllFunctions:
15066 * @ctxt: the XPath context
15067 *
15068 * Registers all default XPath functions in this context
15069 */
15070void
15071xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15072{
15073 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15074 xmlXPathBooleanFunction);
15075 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15076 xmlXPathCeilingFunction);
15077 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15078 xmlXPathCountFunction);
15079 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15080 xmlXPathConcatFunction);
15081 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15082 xmlXPathContainsFunction);
15083 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15084 xmlXPathIdFunction);
15085 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15086 xmlXPathFalseFunction);
15087 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15088 xmlXPathFloorFunction);
15089 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15090 xmlXPathLastFunction);
15091 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15092 xmlXPathLangFunction);
15093 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15094 xmlXPathLocalNameFunction);
15095 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15096 xmlXPathNotFunction);
15097 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15098 xmlXPathNameFunction);
15099 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15100 xmlXPathNamespaceURIFunction);
15101 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15102 xmlXPathNormalizeFunction);
15103 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15104 xmlXPathNumberFunction);
15105 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15106 xmlXPathPositionFunction);
15107 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15108 xmlXPathRoundFunction);
15109 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15110 xmlXPathStringFunction);
15111 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15112 xmlXPathStringLengthFunction);
15113 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15114 xmlXPathStartsWithFunction);
15115 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15116 xmlXPathSubstringFunction);
15117 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15118 xmlXPathSubstringBeforeFunction);
15119 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15120 xmlXPathSubstringAfterFunction);
15121 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15122 xmlXPathSumFunction);
15123 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15124 xmlXPathTrueFunction);
15125 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15126 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000015127
15128 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15129 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15130 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000015131}
15132
15133#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000015134#define bottom_xpath
15135#include "elfgcchack.h"