blob: 70b99c0106f7ffa3f7c50e5c28c0214e5f791ebe [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005 *f
Owen Taylor3473f882001-02-23 17:55:21 +00006 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011 * See Copyright for the status of this software
Owen Taylor3473f882001-02-23 17:55:21 +000012 *
Daniel Veillardc5d64342001-06-24 12:13:24 +000013 * Author: daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000014 *
Owen Taylor3473f882001-02-23 17:55:21 +000015 */
16
Daniel Veillard34ce8be2002-03-18 19:37:11 +000017#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000018#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000019
Owen Taylor3473f882001-02-23 17:55:21 +000020#include <string.h>
21
22#ifdef HAVE_SYS_TYPES_H
23#include <sys/types.h>
24#endif
25#ifdef HAVE_MATH_H
26#include <math.h>
27#endif
28#ifdef HAVE_FLOAT_H
29#include <float.h>
30#endif
Owen Taylor3473f882001-02-23 17:55:21 +000031#ifdef HAVE_CTYPE_H
32#include <ctype.h>
33#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000034#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000035#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000036#endif
Owen Taylor3473f882001-02-23 17:55:21 +000037
38#include <libxml/xmlmemory.h>
39#include <libxml/tree.h>
40#include <libxml/valid.h>
41#include <libxml/xpath.h>
42#include <libxml/xpathInternals.h>
43#include <libxml/parserInternals.h>
44#include <libxml/hash.h>
45#ifdef LIBXML_XPTR_ENABLED
46#include <libxml/xpointer.h>
47#endif
48#ifdef LIBXML_DEBUG_ENABLED
49#include <libxml/debugXML.h>
50#endif
51#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000052#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000053#include <libxml/globals.h>
Daniel Veillard56de87e2005-02-16 00:22:29 +000054#ifdef LIBXML_PATTERN_ENABLED
55#include <libxml/pattern.h>
56#endif
57
Daniel Veillardade10f22012-07-12 09:43:27 +080058#include "buf.h"
59
Daniel Veillard56de87e2005-02-16 00:22:29 +000060#ifdef LIBXML_PATTERN_ENABLED
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000061#define XPATH_STREAMING
Daniel Veillard56de87e2005-02-16 00:22:29 +000062#endif
Owen Taylor3473f882001-02-23 17:55:21 +000063
Daniel Veillard45490ae2008-07-29 09:13:19 +000064#define TODO \
Daniel Veillardd96f6d32003-10-07 21:25:12 +000065 xmlGenericError(xmlGenericErrorContext, \
66 "Unimplemented block at %s:%d\n", \
67 __FILE__, __LINE__);
68
William M. Brackd1757ab2004-10-02 22:07:48 +000069/*
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000070* XP_OPTIMIZED_NON_ELEM_COMPARISON:
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +000071* If defined, this will use xmlXPathCmpNodesExt() instead of
72* xmlXPathCmpNodes(). The new function is optimized comparison of
73* non-element nodes; actually it will speed up comparison only if
74* xmlXPathOrderDocElems() was called in order to index the elements of
75* a tree in document order; Libxslt does such an indexing, thus it will
76* benefit from this optimization.
77*/
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000078#define XP_OPTIMIZED_NON_ELEM_COMPARISON
79
80/*
81* XP_OPTIMIZED_FILTER_FIRST:
82* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
83* in a way, that it stop evaluation at the first node.
Daniel Veillard45490ae2008-07-29 09:13:19 +000084*/
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000085#define XP_OPTIMIZED_FILTER_FIRST
86
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000087/*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000088* XP_DEBUG_OBJ_USAGE:
89* Internal flag to enable tracking of how much XPath objects have been
90* created.
91*/
92/* #define XP_DEBUG_OBJ_USAGE */
93
94/*
William M. Brackd1757ab2004-10-02 22:07:48 +000095 * TODO:
96 * There are a few spots where some tests are done which depend upon ascii
97 * data. These should be enhanced for full UTF8 support (see particularly
98 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
99 */
Kasimier T. Buchcik97258712006-01-05 12:30:43 +0000100
William M. Brack21e4ef22005-01-02 09:53:13 +0000101#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000102
103/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000104 * *
105 * Floating point stuff *
106 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000107 ************************************************************************/
108
Daniel Veillardc0631a62001-09-20 13:56:06 +0000109#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +0000110#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +0000111#endif
Daniel Veillardcda96922001-08-21 10:56:31 +0000112#include "trionan.c"
113
Owen Taylor3473f882001-02-23 17:55:21 +0000114/*
Owen Taylor3473f882001-02-23 17:55:21 +0000115 * The lack of portability of this section of the libc is annoying !
116 */
117double xmlXPathNAN = 0;
118double xmlXPathPINF = 1;
119double xmlXPathNINF = -1;
Daniel Veillard24505b02005-07-28 23:49:35 +0000120static double xmlXPathNZERO = 0; /* not exported from headers */
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000121static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000122
Owen Taylor3473f882001-02-23 17:55:21 +0000123/**
124 * xmlXPathInit:
125 *
126 * Initialize the XPath environment
127 */
128void
129xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000130 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +0000131
Bjorn Reese45029602001-08-21 09:23:53 +0000132 xmlXPathPINF = trio_pinf();
133 xmlXPathNINF = trio_ninf();
134 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000135 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +0000136
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000137 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000138}
139
Daniel Veillardcda96922001-08-21 10:56:31 +0000140/**
141 * xmlXPathIsNaN:
142 * @val: a double value
143 *
144 * Provides a portable isnan() function to detect whether a double
145 * is a NotaNumber. Based on trio code
146 * http://sourceforge.net/projects/ctrio/
Daniel Veillard45490ae2008-07-29 09:13:19 +0000147 *
Daniel Veillardcda96922001-08-21 10:56:31 +0000148 * Returns 1 if the value is a NaN, 0 otherwise
149 */
150int
151xmlXPathIsNaN(double val) {
152 return(trio_isnan(val));
153}
154
155/**
156 * xmlXPathIsInf:
157 * @val: a double value
158 *
159 * Provides a portable isinf() function to detect whether a double
160 * is a +Infinite or -Infinite. Based on trio code
161 * http://sourceforge.net/projects/ctrio/
Daniel Veillard45490ae2008-07-29 09:13:19 +0000162 *
Daniel Veillardcda96922001-08-21 10:56:31 +0000163 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
164 */
165int
166xmlXPathIsInf(double val) {
167 return(trio_isinf(val));
168}
169
Daniel Veillard4432df22003-09-28 18:58:27 +0000170#endif /* SCHEMAS or XPATH */
171#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000172/**
173 * xmlXPathGetSign:
174 * @val: a double value
175 *
176 * Provides a portable function to detect the sign of a double
177 * Modified from trio code
178 * http://sourceforge.net/projects/ctrio/
Daniel Veillard45490ae2008-07-29 09:13:19 +0000179 *
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000180 * Returns 1 if the value is Negative, 0 if positive
181 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000182static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000183xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000184 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000185}
186
187
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000188/*
189 * TODO: when compatibility allows remove all "fake node libxslt" strings
190 * the test should just be name[0] = ' '
191 */
Daniel Veillard074f37e2008-09-01 13:38:22 +0000192#ifdef DEBUG_XPATH_EXPRESSION
193#define DEBUG_STEP
194#define DEBUG_EXPR
195#define DEBUG_EVAL_COUNTS
196#endif
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000197
198static xmlNs xmlXPathXMLNamespaceStruct = {
199 NULL,
200 XML_NAMESPACE_DECL,
201 XML_XML_NAMESPACE,
202 BAD_CAST "xml",
William M. Brackee0b9822007-03-07 08:15:01 +0000203 NULL,
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000204 NULL
205};
206static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
207#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard45490ae2008-07-29 09:13:19 +0000208/*
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000209 * Optimizer is disabled only when threaded apps are detected while
210 * the library ain't compiled for thread safety.
211 */
212static int xmlXPathDisableOptimizer = 0;
213#endif
214
Owen Taylor3473f882001-02-23 17:55:21 +0000215/************************************************************************
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000216 * *
217 * Error handling routines *
218 * *
219 ************************************************************************/
220
Daniel Veillard24505b02005-07-28 23:49:35 +0000221/**
222 * XP_ERRORNULL:
223 * @X: the error code
224 *
225 * Macro to raise an XPath error and return NULL.
226 */
227#define XP_ERRORNULL(X) \
228 { xmlXPathErr(ctxt, X); return(NULL); }
229
William M. Brack08171912003-12-29 02:52:11 +0000230/*
231 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
232 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000233static const char *xmlXPathErrorMessages[] = {
234 "Ok\n",
235 "Number encoding\n",
236 "Unfinished literal\n",
237 "Start of literal\n",
238 "Expected $ for variable reference\n",
239 "Undefined variable\n",
240 "Invalid predicate\n",
241 "Invalid expression\n",
242 "Missing closing curly brace\n",
243 "Unregistered function\n",
244 "Invalid operand\n",
245 "Invalid type\n",
246 "Invalid number of arguments\n",
247 "Invalid context size\n",
248 "Invalid context position\n",
249 "Memory allocation error\n",
250 "Syntax error\n",
251 "Resource error\n",
252 "Sub resource error\n",
253 "Undefined namespace prefix\n",
254 "Encoding error\n",
Daniel Veillard57b25162004-11-06 14:50:18 +0000255 "Char out of XML range\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000256 "Invalid or incomplete context\n",
Daniel Veillardf5048b32011-08-18 17:10:13 +0800257 "Stack usage errror\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000258 "?? Unknown error ??\n" /* Must be last in the list! */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000259};
William M. Brackcd65bc92005-01-06 09:39:18 +0000260#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
261 sizeof(xmlXPathErrorMessages[0])) - 1)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000262/**
263 * xmlXPathErrMemory:
264 * @ctxt: an XPath context
265 * @extra: extra informations
266 *
267 * Handle a redefinition of attribute error
268 */
269static void
270xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
271{
272 if (ctxt != NULL) {
273 if (extra) {
274 xmlChar buf[200];
275
276 xmlStrPrintf(buf, 200,
277 BAD_CAST "Memory allocation failed : %s\n",
278 extra);
279 ctxt->lastError.message = (char *) xmlStrdup(buf);
280 } else {
281 ctxt->lastError.message = (char *)
282 xmlStrdup(BAD_CAST "Memory allocation failed\n");
283 }
284 ctxt->lastError.domain = XML_FROM_XPATH;
285 ctxt->lastError.code = XML_ERR_NO_MEMORY;
286 if (ctxt->error != NULL)
287 ctxt->error(ctxt->userData, &ctxt->lastError);
288 } else {
289 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000290 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000291 NULL, NULL, XML_FROM_XPATH,
292 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
293 extra, NULL, NULL, 0, 0,
294 "Memory allocation failed : %s\n", extra);
295 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000296 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000297 NULL, NULL, XML_FROM_XPATH,
298 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
299 NULL, NULL, NULL, 0, 0,
300 "Memory allocation failed\n");
301 }
302}
303
304/**
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000305 * xmlXPathPErrMemory:
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000306 * @ctxt: an XPath parser context
307 * @extra: extra informations
308 *
309 * Handle a redefinition of attribute error
310 */
311static void
312xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
313{
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000314 if (ctxt == NULL)
315 xmlXPathErrMemory(NULL, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000316 else {
317 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000318 xmlXPathErrMemory(ctxt->context, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000319 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000320}
321
322/**
323 * xmlXPathErr:
324 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000325 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000326 *
William M. Brackcd65bc92005-01-06 09:39:18 +0000327 * Handle an XPath error
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000328 */
329void
330xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
331{
William M. Brackcd65bc92005-01-06 09:39:18 +0000332 if ((error < 0) || (error > MAXERRNO))
333 error = MAXERRNO;
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000334 if (ctxt == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000335 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000336 NULL, NULL, XML_FROM_XPATH,
337 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
338 XML_ERR_ERROR, NULL, 0,
339 NULL, NULL, NULL, 0, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200340 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000341 return;
342 }
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000343 ctxt->error = error;
344 if (ctxt->context == NULL) {
345 __xmlRaiseError(NULL, NULL, NULL,
346 NULL, NULL, XML_FROM_XPATH,
347 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
348 XML_ERR_ERROR, NULL, 0,
349 (const char *) ctxt->base, NULL, NULL,
350 ctxt->cur - ctxt->base, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200351 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000352 return;
353 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +0000354
355 /* cleanup current last error */
Daniel Veillard45490ae2008-07-29 09:13:19 +0000356 xmlResetError(&ctxt->context->lastError);
Aleksey Sanin1b2be102006-05-31 20:53:43 +0000357
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000358 ctxt->context->lastError.domain = XML_FROM_XPATH;
359 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
360 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000361 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000362 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
363 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
364 ctxt->context->lastError.node = ctxt->context->debugNode;
365 if (ctxt->context->error != NULL) {
366 ctxt->context->error(ctxt->context->userData,
367 &ctxt->context->lastError);
368 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000369 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000370 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
371 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
372 XML_ERR_ERROR, NULL, 0,
373 (const char *) ctxt->base, NULL, NULL,
374 ctxt->cur - ctxt->base, 0,
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200375 "%s", xmlXPathErrorMessages[error]);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000376 }
377
378}
379
380/**
381 * xmlXPatherror:
382 * @ctxt: the XPath Parser context
383 * @file: the file name
384 * @line: the line number
385 * @no: the error number
386 *
387 * Formats an error message.
388 */
389void
390xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
391 int line ATTRIBUTE_UNUSED, int no) {
392 xmlXPathErr(ctxt, no);
393}
394
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000395/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000396 * *
397 * Utilities *
398 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000399 ************************************************************************/
400
401/**
402 * xsltPointerList:
403 *
404 * Pointer-list for various purposes.
405 */
406typedef struct _xmlPointerList xmlPointerList;
407typedef xmlPointerList *xmlPointerListPtr;
408struct _xmlPointerList {
409 void **items;
410 int number;
411 int size;
412};
413/*
414* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
415* and here, we should make the functions public.
416*/
417static int
Daniel Veillard45490ae2008-07-29 09:13:19 +0000418xmlPointerListAddSize(xmlPointerListPtr list,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000419 void *item,
420 int initialSize)
421{
422 if (list->items == NULL) {
423 if (initialSize <= 0)
424 initialSize = 1;
425 list->items = (void **) xmlMalloc(
426 initialSize * sizeof(void *));
427 if (list->items == NULL) {
428 xmlXPathErrMemory(NULL,
429 "xmlPointerListCreate: allocating item\n");
430 return(-1);
431 }
432 list->number = 0;
433 list->size = initialSize;
434 } else if (list->size <= list->number) {
435 list->size *= 2;
436 list->items = (void **) xmlRealloc(list->items,
437 list->size * sizeof(void *));
438 if (list->items == NULL) {
439 xmlXPathErrMemory(NULL,
440 "xmlPointerListCreate: re-allocating item\n");
441 list->size = 0;
442 return(-1);
443 }
444 }
445 list->items[list->number++] = item;
446 return(0);
447}
448
449/**
450 * xsltPointerListCreate:
451 *
452 * Creates an xsltPointerList structure.
453 *
454 * Returns a xsltPointerList structure or NULL in case of an error.
455 */
456static xmlPointerListPtr
457xmlPointerListCreate(int initialSize)
458{
459 xmlPointerListPtr ret;
460
461 ret = xmlMalloc(sizeof(xmlPointerList));
462 if (ret == NULL) {
463 xmlXPathErrMemory(NULL,
464 "xmlPointerListCreate: allocating item\n");
465 return (NULL);
466 }
467 memset(ret, 0, sizeof(xmlPointerList));
468 if (initialSize > 0) {
469 xmlPointerListAddSize(ret, NULL, initialSize);
470 ret->number = 0;
471 }
472 return (ret);
473}
474
475/**
476 * xsltPointerListFree:
477 *
478 * Frees the xsltPointerList structure. This does not free
479 * the content of the list.
480 */
481static void
482xmlPointerListFree(xmlPointerListPtr list)
483{
484 if (list == NULL)
485 return;
486 if (list->items != NULL)
487 xmlFree(list->items);
488 xmlFree(list);
489}
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000490
491/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000492 * *
493 * Parser Types *
494 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000495 ************************************************************************/
496
497/*
498 * Types are private:
499 */
500
501typedef enum {
502 XPATH_OP_END=0,
503 XPATH_OP_AND,
504 XPATH_OP_OR,
505 XPATH_OP_EQUAL,
506 XPATH_OP_CMP,
507 XPATH_OP_PLUS,
508 XPATH_OP_MULT,
509 XPATH_OP_UNION,
510 XPATH_OP_ROOT,
511 XPATH_OP_NODE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000512 XPATH_OP_RESET, /* 10 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000513 XPATH_OP_COLLECT,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000514 XPATH_OP_VALUE, /* 12 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000515 XPATH_OP_VARIABLE,
516 XPATH_OP_FUNCTION,
517 XPATH_OP_ARG,
518 XPATH_OP_PREDICATE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000519 XPATH_OP_FILTER, /* 17 */
520 XPATH_OP_SORT /* 18 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000521#ifdef LIBXML_XPTR_ENABLED
522 ,XPATH_OP_RANGETO
523#endif
524} xmlXPathOp;
525
526typedef enum {
527 AXIS_ANCESTOR = 1,
528 AXIS_ANCESTOR_OR_SELF,
529 AXIS_ATTRIBUTE,
530 AXIS_CHILD,
531 AXIS_DESCENDANT,
532 AXIS_DESCENDANT_OR_SELF,
533 AXIS_FOLLOWING,
534 AXIS_FOLLOWING_SIBLING,
535 AXIS_NAMESPACE,
536 AXIS_PARENT,
537 AXIS_PRECEDING,
538 AXIS_PRECEDING_SIBLING,
Daniel Veillard45490ae2008-07-29 09:13:19 +0000539 AXIS_SELF
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000540} xmlXPathAxisVal;
541
542typedef enum {
543 NODE_TEST_NONE = 0,
544 NODE_TEST_TYPE = 1,
545 NODE_TEST_PI = 2,
546 NODE_TEST_ALL = 3,
547 NODE_TEST_NS = 4,
548 NODE_TEST_NAME = 5
549} xmlXPathTestVal;
550
551typedef enum {
552 NODE_TYPE_NODE = 0,
553 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
554 NODE_TYPE_TEXT = XML_TEXT_NODE,
Daniel Veillard45490ae2008-07-29 09:13:19 +0000555 NODE_TYPE_PI = XML_PI_NODE
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000556} xmlXPathTypeVal;
557
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +0000558#define XP_REWRITE_DOS_CHILD_ELEM 1
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000559
560typedef struct _xmlXPathStepOp xmlXPathStepOp;
561typedef xmlXPathStepOp *xmlXPathStepOpPtr;
562struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000563 xmlXPathOp op; /* The identifier of the operation */
564 int ch1; /* First child */
565 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000566 int value;
567 int value2;
568 int value3;
569 void *value4;
570 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000571 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000572 void *cacheURI;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +0000573 int rewriteType;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000574};
575
576struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000577 int nbStep; /* Number of steps in this expression */
578 int maxStep; /* Maximum number of steps allocated */
579 xmlXPathStepOp *steps; /* ops for computation of this expression */
580 int last; /* index of last step in expression */
581 xmlChar *expr; /* the expression being computed */
Daniel Veillard4773df22004-01-23 13:15:13 +0000582 xmlDictPtr dict; /* the dictionnary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000583#ifdef DEBUG_EVAL_COUNTS
584 int nb;
585 xmlChar *string;
586#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000587#ifdef XPATH_STREAMING
588 xmlPatternPtr stream;
589#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000590};
591
592/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000593 * *
594 * Forward declarations *
595 * *
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000596 ************************************************************************/
597static void
598xmlXPathFreeValueTree(xmlNodeSetPtr obj);
599static void
600xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
601static int
602xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
603 xmlXPathStepOpPtr op, xmlNodePtr *first);
604static int
605xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +0000606 xmlXPathStepOpPtr op,
607 int isPredicate);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000608
609/************************************************************************
Daniel Veillard45490ae2008-07-29 09:13:19 +0000610 * *
611 * Parser Type functions *
612 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000613 ************************************************************************/
614
615/**
616 * xmlXPathNewCompExpr:
617 *
618 * Create a new Xpath component
619 *
620 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
621 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000622static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000623xmlXPathNewCompExpr(void) {
624 xmlXPathCompExprPtr cur;
625
626 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
627 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000628 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000629 return(NULL);
630 }
631 memset(cur, 0, sizeof(xmlXPathCompExpr));
632 cur->maxStep = 10;
633 cur->nbStep = 0;
634 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
635 sizeof(xmlXPathStepOp));
636 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000637 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000638 xmlFree(cur);
639 return(NULL);
640 }
641 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
642 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000643#ifdef DEBUG_EVAL_COUNTS
644 cur->nb = 0;
645#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000646 return(cur);
647}
648
649/**
650 * xmlXPathFreeCompExpr:
651 * @comp: an XPATH comp
652 *
653 * Free up the memory allocated by @comp
654 */
655void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000656xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
657{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000658 xmlXPathStepOpPtr op;
659 int i;
660
661 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000662 return;
Daniel Veillard4773df22004-01-23 13:15:13 +0000663 if (comp->dict == NULL) {
664 for (i = 0; i < comp->nbStep; i++) {
665 op = &comp->steps[i];
666 if (op->value4 != NULL) {
667 if (op->op == XPATH_OP_VALUE)
668 xmlXPathFreeObject(op->value4);
669 else
670 xmlFree(op->value4);
671 }
672 if (op->value5 != NULL)
673 xmlFree(op->value5);
674 }
675 } else {
676 for (i = 0; i < comp->nbStep; i++) {
677 op = &comp->steps[i];
678 if (op->value4 != NULL) {
679 if (op->op == XPATH_OP_VALUE)
680 xmlXPathFreeObject(op->value4);
681 }
682 }
683 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000684 }
685 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000686 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000687 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000688#ifdef DEBUG_EVAL_COUNTS
689 if (comp->string != NULL) {
690 xmlFree(comp->string);
691 }
692#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000693#ifdef XPATH_STREAMING
694 if (comp->stream != NULL) {
695 xmlFreePatternList(comp->stream);
696 }
697#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000698 if (comp->expr != NULL) {
699 xmlFree(comp->expr);
700 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000701
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000702 xmlFree(comp);
703}
704
705/**
706 * xmlXPathCompExprAdd:
707 * @comp: the compiled expression
708 * @ch1: first child index
709 * @ch2: second child index
710 * @op: an op
711 * @value: the first int value
712 * @value2: the second int value
713 * @value3: the third int value
714 * @value4: the first string value
715 * @value5: the second string value
716 *
William M. Brack08171912003-12-29 02:52:11 +0000717 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000718 *
719 * Returns -1 in case of failure, the index otherwise
720 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000721static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000722xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
723 xmlXPathOp op, int value,
724 int value2, int value3, void *value4, void *value5) {
725 if (comp->nbStep >= comp->maxStep) {
726 xmlXPathStepOp *real;
727
728 comp->maxStep *= 2;
729 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
730 comp->maxStep * sizeof(xmlXPathStepOp));
731 if (real == NULL) {
732 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000733 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000734 return(-1);
735 }
736 comp->steps = real;
737 }
738 comp->last = comp->nbStep;
Kasimier T. Buchcik6422d912006-06-26 14:31:53 +0000739 comp->steps[comp->nbStep].rewriteType = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000740 comp->steps[comp->nbStep].ch1 = ch1;
741 comp->steps[comp->nbStep].ch2 = ch2;
742 comp->steps[comp->nbStep].op = op;
743 comp->steps[comp->nbStep].value = value;
744 comp->steps[comp->nbStep].value2 = value2;
745 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +0000746 if ((comp->dict != NULL) &&
747 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
748 (op == XPATH_OP_COLLECT))) {
749 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000750 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000751 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000752 xmlFree(value4);
753 } else
754 comp->steps[comp->nbStep].value4 = NULL;
755 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000756 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000757 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000758 xmlFree(value5);
759 } else
760 comp->steps[comp->nbStep].value5 = NULL;
761 } else {
762 comp->steps[comp->nbStep].value4 = value4;
763 comp->steps[comp->nbStep].value5 = value5;
764 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000765 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000766 return(comp->nbStep++);
767}
768
Daniel Veillardf06307e2001-07-03 10:35:50 +0000769/**
770 * xmlXPathCompSwap:
771 * @comp: the compiled expression
772 * @op: operation index
773 *
774 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000775 */
776static void
777xmlXPathCompSwap(xmlXPathStepOpPtr op) {
778 int tmp;
779
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000780#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000781 /*
782 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +0000783 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +0000784 * application
785 */
786 if (xmlXPathDisableOptimizer)
787 return;
788#endif
789
Daniel Veillardf06307e2001-07-03 10:35:50 +0000790 tmp = op->ch1;
791 op->ch1 = op->ch2;
792 op->ch2 = tmp;
793}
794
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000795#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
796 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
797 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000798#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
799 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
800 (op), (val), (val2), (val3), (val4), (val5))
801
Daniel Veillard45490ae2008-07-29 09:13:19 +0000802#define PUSH_LEAVE_EXPR(op, val, val2) \
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000803xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
804
Daniel Veillard45490ae2008-07-29 09:13:19 +0000805#define PUSH_UNARY_EXPR(op, ch, val, val2) \
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000806xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
807
Daniel Veillard45490ae2008-07-29 09:13:19 +0000808#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +0000809xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
810 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000811
812/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000813 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +0000814 * XPath object cache structures *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000815 * *
816 ************************************************************************/
817
818/* #define XP_DEFAULT_CACHE_ON */
819
Kasimier T. Buchcik58694692006-05-31 12:37:28 +0000820#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000821
Kasimier T. Buchcik58694692006-05-31 12:37:28 +0000822typedef struct _xmlXPathContextCache xmlXPathContextCache;
823typedef xmlXPathContextCache *xmlXPathContextCachePtr;
824struct _xmlXPathContextCache {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +0000825 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
826 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
827 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
828 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
829 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000830 int maxNodeset;
831 int maxString;
832 int maxBoolean;
833 int maxNumber;
834 int maxMisc;
835#ifdef XP_DEBUG_OBJ_USAGE
836 int dbgCachedAll;
837 int dbgCachedNodeset;
838 int dbgCachedString;
839 int dbgCachedBool;
840 int dbgCachedNumber;
841 int dbgCachedPoint;
842 int dbgCachedRange;
843 int dbgCachedLocset;
844 int dbgCachedUsers;
845 int dbgCachedXSLTTree;
Daniel Veillard45490ae2008-07-29 09:13:19 +0000846 int dbgCachedUndefined;
847
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000848
849 int dbgReusedAll;
850 int dbgReusedNodeset;
851 int dbgReusedString;
852 int dbgReusedBool;
853 int dbgReusedNumber;
854 int dbgReusedPoint;
855 int dbgReusedRange;
856 int dbgReusedLocset;
857 int dbgReusedUsers;
858 int dbgReusedXSLTTree;
859 int dbgReusedUndefined;
860
861#endif
862};
863
864/************************************************************************
865 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +0000866 * Debugging related functions *
Owen Taylor3473f882001-02-23 17:55:21 +0000867 * *
868 ************************************************************************/
869
Daniel Veillard45490ae2008-07-29 09:13:19 +0000870#define STRANGE \
Owen Taylor3473f882001-02-23 17:55:21 +0000871 xmlGenericError(xmlGenericErrorContext, \
872 "Internal error at %s:%d\n", \
873 __FILE__, __LINE__);
874
875#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000876static void
877xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000878 int i;
879 char shift[100];
880
881 for (i = 0;((i < depth) && (i < 25));i++)
882 shift[2 * i] = shift[2 * i + 1] = ' ';
883 shift[2 * i] = shift[2 * i + 1] = 0;
884 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200885 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +0000886 fprintf(output, "Node is NULL !\n");
887 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +0000888
Owen Taylor3473f882001-02-23 17:55:21 +0000889 }
890
891 if ((cur->type == XML_DOCUMENT_NODE) ||
892 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200893 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +0000894 fprintf(output, " /\n");
895 } else if (cur->type == XML_ATTRIBUTE_NODE)
896 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
897 else
898 xmlDebugDumpOneNode(output, cur, depth);
899}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000900static void
901xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000902 xmlNodePtr tmp;
903 int i;
904 char shift[100];
905
906 for (i = 0;((i < depth) && (i < 25));i++)
907 shift[2 * i] = shift[2 * i + 1] = ' ';
908 shift[2 * i] = shift[2 * i + 1] = 0;
909 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200910 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000911 fprintf(output, "Node is NULL !\n");
912 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +0000913
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000914 }
915
916 while (cur != NULL) {
917 tmp = cur;
918 cur = cur->next;
919 xmlDebugDumpOneNode(output, tmp, depth);
920 }
921}
Owen Taylor3473f882001-02-23 17:55:21 +0000922
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000923static void
924xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000925 int i;
926 char shift[100];
927
928 for (i = 0;((i < depth) && (i < 25));i++)
929 shift[2 * i] = shift[2 * i + 1] = ' ';
930 shift[2 * i] = shift[2 * i + 1] = 0;
931
932 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200933 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +0000934 fprintf(output, "NodeSet is NULL !\n");
935 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +0000936
Owen Taylor3473f882001-02-23 17:55:21 +0000937 }
938
Daniel Veillard911f49a2001-04-07 15:39:35 +0000939 if (cur != NULL) {
940 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
941 for (i = 0;i < cur->nodeNr;i++) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200942 fprintf(output, "%s", shift);
Daniel Veillard911f49a2001-04-07 15:39:35 +0000943 fprintf(output, "%d", i + 1);
944 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
945 }
Owen Taylor3473f882001-02-23 17:55:21 +0000946 }
947}
948
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000949static void
950xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000951 int i;
952 char shift[100];
953
954 for (i = 0;((i < depth) && (i < 25));i++)
955 shift[2 * i] = shift[2 * i + 1] = ' ';
956 shift[2 * i] = shift[2 * i + 1] = 0;
957
958 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200959 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000960 fprintf(output, "Value Tree is NULL !\n");
961 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +0000962
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000963 }
964
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200965 fprintf(output, "%s", shift);
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000966 fprintf(output, "%d", i + 1);
967 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
968}
Owen Taylor3473f882001-02-23 17:55:21 +0000969#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000970static void
971xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000972 int i;
973 char shift[100];
974
975 for (i = 0;((i < depth) && (i < 25));i++)
976 shift[2 * i] = shift[2 * i + 1] = ' ';
977 shift[2 * i] = shift[2 * i + 1] = 0;
978
979 if (cur == NULL) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200980 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +0000981 fprintf(output, "LocationSet is NULL !\n");
982 return;
Daniel Veillard45490ae2008-07-29 09:13:19 +0000983
Owen Taylor3473f882001-02-23 17:55:21 +0000984 }
985
986 for (i = 0;i < cur->locNr;i++) {
Daniel Veillardbccae2d2009-06-04 11:22:45 +0200987 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +0000988 fprintf(output, "%d : ", i + 1);
989 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
990 }
991}
Daniel Veillard017b1082001-06-21 11:20:21 +0000992#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000993
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000994/**
995 * xmlXPathDebugDumpObject:
996 * @output: the FILE * to dump the output
997 * @cur: the object to inspect
998 * @depth: indentation level
999 *
1000 * Dump the content of the object for debugging purposes
1001 */
1002void
1003xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001004 int i;
1005 char shift[100];
1006
Daniel Veillarda82b1822004-11-08 16:24:57 +00001007 if (output == NULL) return;
1008
Owen Taylor3473f882001-02-23 17:55:21 +00001009 for (i = 0;((i < depth) && (i < 25));i++)
1010 shift[2 * i] = shift[2 * i + 1] = ' ';
1011 shift[2 * i] = shift[2 * i + 1] = 0;
1012
Kasimier T. Buchcik97258712006-01-05 12:30:43 +00001013
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001014 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001015
1016 if (cur == NULL) {
1017 fprintf(output, "Object is empty (NULL)\n");
1018 return;
1019 }
1020 switch(cur->type) {
1021 case XPATH_UNDEFINED:
1022 fprintf(output, "Object is uninitialized\n");
1023 break;
1024 case XPATH_NODESET:
1025 fprintf(output, "Object is a Node Set :\n");
1026 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1027 break;
1028 case XPATH_XSLT_TREE:
1029 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001030 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +00001031 break;
1032 case XPATH_BOOLEAN:
1033 fprintf(output, "Object is a Boolean : ");
1034 if (cur->boolval) fprintf(output, "true\n");
1035 else fprintf(output, "false\n");
1036 break;
1037 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +00001038 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001039 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001040 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001041 break;
1042 case -1:
1043 fprintf(output, "Object is a number : -Infinity\n");
1044 break;
1045 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001046 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001047 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001048 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1049 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001050 } else {
1051 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1052 }
1053 }
Owen Taylor3473f882001-02-23 17:55:21 +00001054 break;
1055 case XPATH_STRING:
1056 fprintf(output, "Object is a string : ");
1057 xmlDebugDumpString(output, cur->stringval);
1058 fprintf(output, "\n");
1059 break;
1060 case XPATH_POINT:
1061 fprintf(output, "Object is a point : index %d in node", cur->index);
1062 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1063 fprintf(output, "\n");
1064 break;
1065 case XPATH_RANGE:
1066 if ((cur->user2 == NULL) ||
1067 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1068 fprintf(output, "Object is a collapsed range :\n");
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001069 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001070 if (cur->index >= 0)
1071 fprintf(output, "index %d in ", cur->index);
1072 fprintf(output, "node\n");
1073 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1074 depth + 1);
1075 } else {
1076 fprintf(output, "Object is a range :\n");
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001077 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001078 fprintf(output, "From ");
1079 if (cur->index >= 0)
1080 fprintf(output, "index %d in ", cur->index);
1081 fprintf(output, "node\n");
1082 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1083 depth + 1);
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001084 fprintf(output, "%s", shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001085 fprintf(output, "To ");
1086 if (cur->index2 >= 0)
1087 fprintf(output, "index %d in ", cur->index2);
1088 fprintf(output, "node\n");
1089 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1090 depth + 1);
1091 fprintf(output, "\n");
1092 }
1093 break;
1094 case XPATH_LOCATIONSET:
1095#if defined(LIBXML_XPTR_ENABLED)
1096 fprintf(output, "Object is a Location Set:\n");
1097 xmlXPathDebugDumpLocationSet(output,
1098 (xmlLocationSetPtr) cur->user, depth);
1099#endif
1100 break;
1101 case XPATH_USERS:
1102 fprintf(output, "Object is user defined\n");
1103 break;
1104 }
1105}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001106
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001107static void
1108xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001109 xmlXPathStepOpPtr op, int depth) {
1110 int i;
1111 char shift[100];
1112
1113 for (i = 0;((i < depth) && (i < 25));i++)
1114 shift[2 * i] = shift[2 * i + 1] = ' ';
1115 shift[2 * i] = shift[2 * i + 1] = 0;
1116
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001117 fprintf(output, "%s", shift);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001118 if (op == NULL) {
1119 fprintf(output, "Step is NULL\n");
1120 return;
1121 }
1122 switch (op->op) {
1123 case XPATH_OP_END:
1124 fprintf(output, "END"); break;
1125 case XPATH_OP_AND:
1126 fprintf(output, "AND"); break;
1127 case XPATH_OP_OR:
1128 fprintf(output, "OR"); break;
1129 case XPATH_OP_EQUAL:
1130 if (op->value)
1131 fprintf(output, "EQUAL =");
1132 else
1133 fprintf(output, "EQUAL !=");
1134 break;
1135 case XPATH_OP_CMP:
1136 if (op->value)
1137 fprintf(output, "CMP <");
1138 else
1139 fprintf(output, "CMP >");
1140 if (!op->value2)
1141 fprintf(output, "=");
1142 break;
1143 case XPATH_OP_PLUS:
1144 if (op->value == 0)
1145 fprintf(output, "PLUS -");
1146 else if (op->value == 1)
1147 fprintf(output, "PLUS +");
1148 else if (op->value == 2)
1149 fprintf(output, "PLUS unary -");
1150 else if (op->value == 3)
1151 fprintf(output, "PLUS unary - -");
1152 break;
1153 case XPATH_OP_MULT:
1154 if (op->value == 0)
1155 fprintf(output, "MULT *");
1156 else if (op->value == 1)
1157 fprintf(output, "MULT div");
1158 else
1159 fprintf(output, "MULT mod");
1160 break;
1161 case XPATH_OP_UNION:
1162 fprintf(output, "UNION"); break;
1163 case XPATH_OP_ROOT:
1164 fprintf(output, "ROOT"); break;
1165 case XPATH_OP_NODE:
1166 fprintf(output, "NODE"); break;
1167 case XPATH_OP_RESET:
1168 fprintf(output, "RESET"); break;
1169 case XPATH_OP_SORT:
1170 fprintf(output, "SORT"); break;
1171 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +00001172 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1173 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1174 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001175 const xmlChar *prefix = op->value4;
1176 const xmlChar *name = op->value5;
1177
1178 fprintf(output, "COLLECT ");
1179 switch (axis) {
1180 case AXIS_ANCESTOR:
1181 fprintf(output, " 'ancestors' "); break;
1182 case AXIS_ANCESTOR_OR_SELF:
1183 fprintf(output, " 'ancestors-or-self' "); break;
1184 case AXIS_ATTRIBUTE:
1185 fprintf(output, " 'attributes' "); break;
1186 case AXIS_CHILD:
1187 fprintf(output, " 'child' "); break;
1188 case AXIS_DESCENDANT:
1189 fprintf(output, " 'descendant' "); break;
1190 case AXIS_DESCENDANT_OR_SELF:
1191 fprintf(output, " 'descendant-or-self' "); break;
1192 case AXIS_FOLLOWING:
1193 fprintf(output, " 'following' "); break;
1194 case AXIS_FOLLOWING_SIBLING:
1195 fprintf(output, " 'following-siblings' "); break;
1196 case AXIS_NAMESPACE:
1197 fprintf(output, " 'namespace' "); break;
1198 case AXIS_PARENT:
1199 fprintf(output, " 'parent' "); break;
1200 case AXIS_PRECEDING:
1201 fprintf(output, " 'preceding' "); break;
1202 case AXIS_PRECEDING_SIBLING:
1203 fprintf(output, " 'preceding-sibling' "); break;
1204 case AXIS_SELF:
1205 fprintf(output, " 'self' "); break;
1206 }
1207 switch (test) {
1208 case NODE_TEST_NONE:
1209 fprintf(output, "'none' "); break;
1210 case NODE_TEST_TYPE:
1211 fprintf(output, "'type' "); break;
1212 case NODE_TEST_PI:
1213 fprintf(output, "'PI' "); break;
1214 case NODE_TEST_ALL:
1215 fprintf(output, "'all' "); break;
1216 case NODE_TEST_NS:
1217 fprintf(output, "'namespace' "); break;
1218 case NODE_TEST_NAME:
1219 fprintf(output, "'name' "); break;
1220 }
1221 switch (type) {
1222 case NODE_TYPE_NODE:
1223 fprintf(output, "'node' "); break;
1224 case NODE_TYPE_COMMENT:
1225 fprintf(output, "'comment' "); break;
1226 case NODE_TYPE_TEXT:
1227 fprintf(output, "'text' "); break;
1228 case NODE_TYPE_PI:
1229 fprintf(output, "'PI' "); break;
1230 }
1231 if (prefix != NULL)
1232 fprintf(output, "%s:", prefix);
1233 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001234 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001235 break;
1236
1237 }
1238 case XPATH_OP_VALUE: {
1239 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1240
1241 fprintf(output, "ELEM ");
1242 xmlXPathDebugDumpObject(output, object, 0);
1243 goto finish;
1244 }
1245 case XPATH_OP_VARIABLE: {
1246 const xmlChar *prefix = op->value5;
1247 const xmlChar *name = op->value4;
1248
1249 if (prefix != NULL)
1250 fprintf(output, "VARIABLE %s:%s", prefix, name);
1251 else
1252 fprintf(output, "VARIABLE %s", name);
1253 break;
1254 }
1255 case XPATH_OP_FUNCTION: {
1256 int nbargs = op->value;
1257 const xmlChar *prefix = op->value5;
1258 const xmlChar *name = op->value4;
1259
1260 if (prefix != NULL)
1261 fprintf(output, "FUNCTION %s:%s(%d args)",
1262 prefix, name, nbargs);
1263 else
1264 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1265 break;
1266 }
1267 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1268 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001269 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001270#ifdef LIBXML_XPTR_ENABLED
1271 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1272#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001273 default:
1274 fprintf(output, "UNKNOWN %d\n", op->op); return;
1275 }
1276 fprintf(output, "\n");
1277finish:
1278 if (op->ch1 >= 0)
1279 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1280 if (op->ch2 >= 0)
1281 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1282}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001283
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001284/**
1285 * xmlXPathDebugDumpCompExpr:
1286 * @output: the FILE * for the output
1287 * @comp: the precompiled XPath expression
1288 * @depth: the indentation level.
1289 *
1290 * Dumps the tree of the compiled XPath expression.
1291 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001292void
1293xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1294 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001295 int i;
1296 char shift[100];
1297
Daniel Veillarda82b1822004-11-08 16:24:57 +00001298 if ((output == NULL) || (comp == NULL)) return;
1299
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001300 for (i = 0;((i < depth) && (i < 25));i++)
1301 shift[2 * i] = shift[2 * i + 1] = ' ';
1302 shift[2 * i] = shift[2 * i + 1] = 0;
1303
Daniel Veillardbccae2d2009-06-04 11:22:45 +02001304 fprintf(output, "%s", shift);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001305
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001306 fprintf(output, "Compiled Expression : %d elements\n",
1307 comp->nbStep);
1308 i = comp->last;
1309 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1310}
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001311
1312#ifdef XP_DEBUG_OBJ_USAGE
1313
1314/*
1315* XPath object usage related debugging variables.
1316*/
1317static int xmlXPathDebugObjCounterUndefined = 0;
1318static int xmlXPathDebugObjCounterNodeset = 0;
1319static int xmlXPathDebugObjCounterBool = 0;
1320static int xmlXPathDebugObjCounterNumber = 0;
1321static int xmlXPathDebugObjCounterString = 0;
1322static int xmlXPathDebugObjCounterPoint = 0;
1323static int xmlXPathDebugObjCounterRange = 0;
1324static int xmlXPathDebugObjCounterLocset = 0;
1325static int xmlXPathDebugObjCounterUsers = 0;
1326static int xmlXPathDebugObjCounterXSLTTree = 0;
1327static int xmlXPathDebugObjCounterAll = 0;
1328
1329static int xmlXPathDebugObjTotalUndefined = 0;
1330static int xmlXPathDebugObjTotalNodeset = 0;
1331static int xmlXPathDebugObjTotalBool = 0;
1332static int xmlXPathDebugObjTotalNumber = 0;
1333static int xmlXPathDebugObjTotalString = 0;
1334static int xmlXPathDebugObjTotalPoint = 0;
1335static int xmlXPathDebugObjTotalRange = 0;
1336static int xmlXPathDebugObjTotalLocset = 0;
1337static int xmlXPathDebugObjTotalUsers = 0;
1338static int xmlXPathDebugObjTotalXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001339static int xmlXPathDebugObjTotalAll = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001340
1341static int xmlXPathDebugObjMaxUndefined = 0;
1342static int xmlXPathDebugObjMaxNodeset = 0;
1343static int xmlXPathDebugObjMaxBool = 0;
1344static int xmlXPathDebugObjMaxNumber = 0;
1345static int xmlXPathDebugObjMaxString = 0;
1346static int xmlXPathDebugObjMaxPoint = 0;
1347static int xmlXPathDebugObjMaxRange = 0;
1348static int xmlXPathDebugObjMaxLocset = 0;
1349static int xmlXPathDebugObjMaxUsers = 0;
1350static int xmlXPathDebugObjMaxXSLTTree = 0;
1351static int xmlXPathDebugObjMaxAll = 0;
1352
1353/* REVISIT TODO: Make this static when committing */
1354static void
1355xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1356{
1357 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001358 if (ctxt->cache != NULL) {
1359 xmlXPathContextCachePtr cache =
1360 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001361
1362 cache->dbgCachedAll = 0;
1363 cache->dbgCachedNodeset = 0;
1364 cache->dbgCachedString = 0;
1365 cache->dbgCachedBool = 0;
1366 cache->dbgCachedNumber = 0;
1367 cache->dbgCachedPoint = 0;
1368 cache->dbgCachedRange = 0;
1369 cache->dbgCachedLocset = 0;
1370 cache->dbgCachedUsers = 0;
1371 cache->dbgCachedXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001372 cache->dbgCachedUndefined = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001373
1374 cache->dbgReusedAll = 0;
1375 cache->dbgReusedNodeset = 0;
1376 cache->dbgReusedString = 0;
1377 cache->dbgReusedBool = 0;
1378 cache->dbgReusedNumber = 0;
1379 cache->dbgReusedPoint = 0;
1380 cache->dbgReusedRange = 0;
1381 cache->dbgReusedLocset = 0;
1382 cache->dbgReusedUsers = 0;
1383 cache->dbgReusedXSLTTree = 0;
1384 cache->dbgReusedUndefined = 0;
1385 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00001386 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001387
1388 xmlXPathDebugObjCounterUndefined = 0;
1389 xmlXPathDebugObjCounterNodeset = 0;
1390 xmlXPathDebugObjCounterBool = 0;
1391 xmlXPathDebugObjCounterNumber = 0;
1392 xmlXPathDebugObjCounterString = 0;
1393 xmlXPathDebugObjCounterPoint = 0;
1394 xmlXPathDebugObjCounterRange = 0;
1395 xmlXPathDebugObjCounterLocset = 0;
1396 xmlXPathDebugObjCounterUsers = 0;
1397 xmlXPathDebugObjCounterXSLTTree = 0;
1398 xmlXPathDebugObjCounterAll = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001399
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001400 xmlXPathDebugObjTotalUndefined = 0;
1401 xmlXPathDebugObjTotalNodeset = 0;
1402 xmlXPathDebugObjTotalBool = 0;
1403 xmlXPathDebugObjTotalNumber = 0;
1404 xmlXPathDebugObjTotalString = 0;
1405 xmlXPathDebugObjTotalPoint = 0;
1406 xmlXPathDebugObjTotalRange = 0;
1407 xmlXPathDebugObjTotalLocset = 0;
1408 xmlXPathDebugObjTotalUsers = 0;
1409 xmlXPathDebugObjTotalXSLTTree = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001410 xmlXPathDebugObjTotalAll = 0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001411
1412 xmlXPathDebugObjMaxUndefined = 0;
1413 xmlXPathDebugObjMaxNodeset = 0;
1414 xmlXPathDebugObjMaxBool = 0;
1415 xmlXPathDebugObjMaxNumber = 0;
1416 xmlXPathDebugObjMaxString = 0;
1417 xmlXPathDebugObjMaxPoint = 0;
1418 xmlXPathDebugObjMaxRange = 0;
1419 xmlXPathDebugObjMaxLocset = 0;
1420 xmlXPathDebugObjMaxUsers = 0;
1421 xmlXPathDebugObjMaxXSLTTree = 0;
1422 xmlXPathDebugObjMaxAll = 0;
1423
1424}
1425
1426static void
1427xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1428 xmlXPathObjectType objType)
1429{
1430 int isCached = 0;
1431
1432 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001433 if (ctxt->cache != NULL) {
1434 xmlXPathContextCachePtr cache =
1435 (xmlXPathContextCachePtr) ctxt->cache;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001436
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001437 isCached = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001438
1439 cache->dbgReusedAll++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001440 switch (objType) {
1441 case XPATH_UNDEFINED:
1442 cache->dbgReusedUndefined++;
1443 break;
1444 case XPATH_NODESET:
1445 cache->dbgReusedNodeset++;
1446 break;
1447 case XPATH_BOOLEAN:
1448 cache->dbgReusedBool++;
1449 break;
1450 case XPATH_NUMBER:
1451 cache->dbgReusedNumber++;
1452 break;
1453 case XPATH_STRING:
1454 cache->dbgReusedString++;
1455 break;
1456 case XPATH_POINT:
1457 cache->dbgReusedPoint++;
1458 break;
1459 case XPATH_RANGE:
1460 cache->dbgReusedRange++;
1461 break;
1462 case XPATH_LOCATIONSET:
1463 cache->dbgReusedLocset++;
1464 break;
1465 case XPATH_USERS:
1466 cache->dbgReusedUsers++;
1467 break;
1468 case XPATH_XSLT_TREE:
1469 cache->dbgReusedXSLTTree++;
1470 break;
1471 default:
1472 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001473 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001474 }
1475 }
1476
1477 switch (objType) {
1478 case XPATH_UNDEFINED:
1479 if (! isCached)
1480 xmlXPathDebugObjTotalUndefined++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001481 xmlXPathDebugObjCounterUndefined++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001482 if (xmlXPathDebugObjCounterUndefined >
1483 xmlXPathDebugObjMaxUndefined)
1484 xmlXPathDebugObjMaxUndefined =
1485 xmlXPathDebugObjCounterUndefined;
1486 break;
1487 case XPATH_NODESET:
1488 if (! isCached)
1489 xmlXPathDebugObjTotalNodeset++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001490 xmlXPathDebugObjCounterNodeset++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001491 if (xmlXPathDebugObjCounterNodeset >
1492 xmlXPathDebugObjMaxNodeset)
1493 xmlXPathDebugObjMaxNodeset =
1494 xmlXPathDebugObjCounterNodeset;
1495 break;
1496 case XPATH_BOOLEAN:
1497 if (! isCached)
1498 xmlXPathDebugObjTotalBool++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001499 xmlXPathDebugObjCounterBool++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001500 if (xmlXPathDebugObjCounterBool >
1501 xmlXPathDebugObjMaxBool)
1502 xmlXPathDebugObjMaxBool =
1503 xmlXPathDebugObjCounterBool;
1504 break;
1505 case XPATH_NUMBER:
1506 if (! isCached)
1507 xmlXPathDebugObjTotalNumber++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001508 xmlXPathDebugObjCounterNumber++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001509 if (xmlXPathDebugObjCounterNumber >
1510 xmlXPathDebugObjMaxNumber)
1511 xmlXPathDebugObjMaxNumber =
1512 xmlXPathDebugObjCounterNumber;
1513 break;
1514 case XPATH_STRING:
1515 if (! isCached)
1516 xmlXPathDebugObjTotalString++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001517 xmlXPathDebugObjCounterString++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001518 if (xmlXPathDebugObjCounterString >
1519 xmlXPathDebugObjMaxString)
1520 xmlXPathDebugObjMaxString =
1521 xmlXPathDebugObjCounterString;
1522 break;
1523 case XPATH_POINT:
1524 if (! isCached)
1525 xmlXPathDebugObjTotalPoint++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001526 xmlXPathDebugObjCounterPoint++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001527 if (xmlXPathDebugObjCounterPoint >
1528 xmlXPathDebugObjMaxPoint)
1529 xmlXPathDebugObjMaxPoint =
1530 xmlXPathDebugObjCounterPoint;
1531 break;
1532 case XPATH_RANGE:
1533 if (! isCached)
1534 xmlXPathDebugObjTotalRange++;
1535 xmlXPathDebugObjCounterRange++;
1536 if (xmlXPathDebugObjCounterRange >
1537 xmlXPathDebugObjMaxRange)
1538 xmlXPathDebugObjMaxRange =
1539 xmlXPathDebugObjCounterRange;
1540 break;
1541 case XPATH_LOCATIONSET:
1542 if (! isCached)
1543 xmlXPathDebugObjTotalLocset++;
1544 xmlXPathDebugObjCounterLocset++;
1545 if (xmlXPathDebugObjCounterLocset >
1546 xmlXPathDebugObjMaxLocset)
1547 xmlXPathDebugObjMaxLocset =
1548 xmlXPathDebugObjCounterLocset;
1549 break;
1550 case XPATH_USERS:
1551 if (! isCached)
1552 xmlXPathDebugObjTotalUsers++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001553 xmlXPathDebugObjCounterUsers++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001554 if (xmlXPathDebugObjCounterUsers >
1555 xmlXPathDebugObjMaxUsers)
1556 xmlXPathDebugObjMaxUsers =
1557 xmlXPathDebugObjCounterUsers;
1558 break;
1559 case XPATH_XSLT_TREE:
1560 if (! isCached)
1561 xmlXPathDebugObjTotalXSLTTree++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001562 xmlXPathDebugObjCounterXSLTTree++;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001563 if (xmlXPathDebugObjCounterXSLTTree >
1564 xmlXPathDebugObjMaxXSLTTree)
1565 xmlXPathDebugObjMaxXSLTTree =
1566 xmlXPathDebugObjCounterXSLTTree;
1567 break;
1568 default:
1569 break;
1570 }
1571 if (! isCached)
1572 xmlXPathDebugObjTotalAll++;
1573 xmlXPathDebugObjCounterAll++;
1574 if (xmlXPathDebugObjCounterAll >
1575 xmlXPathDebugObjMaxAll)
1576 xmlXPathDebugObjMaxAll =
1577 xmlXPathDebugObjCounterAll;
1578}
1579
1580static void
1581xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1582 xmlXPathObjectType objType)
1583{
1584 int isCached = 0;
1585
1586 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001587 if (ctxt->cache != NULL) {
1588 xmlXPathContextCachePtr cache =
1589 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001590
Daniel Veillard45490ae2008-07-29 09:13:19 +00001591 isCached = 1;
1592
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001593 cache->dbgCachedAll++;
1594 switch (objType) {
1595 case XPATH_UNDEFINED:
1596 cache->dbgCachedUndefined++;
1597 break;
1598 case XPATH_NODESET:
1599 cache->dbgCachedNodeset++;
1600 break;
1601 case XPATH_BOOLEAN:
1602 cache->dbgCachedBool++;
1603 break;
1604 case XPATH_NUMBER:
1605 cache->dbgCachedNumber++;
1606 break;
1607 case XPATH_STRING:
1608 cache->dbgCachedString++;
1609 break;
1610 case XPATH_POINT:
1611 cache->dbgCachedPoint++;
1612 break;
1613 case XPATH_RANGE:
1614 cache->dbgCachedRange++;
1615 break;
1616 case XPATH_LOCATIONSET:
1617 cache->dbgCachedLocset++;
1618 break;
1619 case XPATH_USERS:
1620 cache->dbgCachedUsers++;
1621 break;
1622 case XPATH_XSLT_TREE:
1623 cache->dbgCachedXSLTTree++;
1624 break;
1625 default:
1626 break;
1627 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00001628
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001629 }
1630 }
1631 switch (objType) {
1632 case XPATH_UNDEFINED:
1633 xmlXPathDebugObjCounterUndefined--;
1634 break;
1635 case XPATH_NODESET:
1636 xmlXPathDebugObjCounterNodeset--;
1637 break;
1638 case XPATH_BOOLEAN:
1639 xmlXPathDebugObjCounterBool--;
1640 break;
1641 case XPATH_NUMBER:
1642 xmlXPathDebugObjCounterNumber--;
1643 break;
1644 case XPATH_STRING:
1645 xmlXPathDebugObjCounterString--;
1646 break;
1647 case XPATH_POINT:
1648 xmlXPathDebugObjCounterPoint--;
1649 break;
1650 case XPATH_RANGE:
1651 xmlXPathDebugObjCounterRange--;
1652 break;
1653 case XPATH_LOCATIONSET:
1654 xmlXPathDebugObjCounterLocset--;
1655 break;
1656 case XPATH_USERS:
1657 xmlXPathDebugObjCounterUsers--;
1658 break;
1659 case XPATH_XSLT_TREE:
1660 xmlXPathDebugObjCounterXSLTTree--;
1661 break;
1662 default:
1663 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001664 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001665 xmlXPathDebugObjCounterAll--;
1666}
1667
1668/* REVISIT TODO: Make this static when committing */
1669static void
1670xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
1671{
1672 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
1673 reqXSLTTree, reqUndefined;
1674 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
1675 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
1676 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
1677 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
1678 int leftObjs = xmlXPathDebugObjCounterAll;
1679
1680 reqAll = xmlXPathDebugObjTotalAll;
1681 reqNodeset = xmlXPathDebugObjTotalNodeset;
1682 reqString = xmlXPathDebugObjTotalString;
1683 reqBool = xmlXPathDebugObjTotalBool;
1684 reqNumber = xmlXPathDebugObjTotalNumber;
1685 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
1686 reqUndefined = xmlXPathDebugObjTotalUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001687
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001688 printf("# XPath object usage:\n");
1689
1690 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001691 if (ctxt->cache != NULL) {
1692 xmlXPathContextCachePtr cache =
1693 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001694
1695 reAll = cache->dbgReusedAll;
1696 reqAll += reAll;
1697 reNodeset = cache->dbgReusedNodeset;
1698 reqNodeset += reNodeset;
1699 reString = cache->dbgReusedString;
1700 reqString += reString;
1701 reBool = cache->dbgReusedBool;
1702 reqBool += reBool;
1703 reNumber = cache->dbgReusedNumber;
1704 reqNumber += reNumber;
1705 reXSLTTree = cache->dbgReusedXSLTTree;
1706 reqXSLTTree += reXSLTTree;
1707 reUndefined = cache->dbgReusedUndefined;
1708 reqUndefined += reUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001709
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001710 caAll = cache->dbgCachedAll;
1711 caBool = cache->dbgCachedBool;
1712 caNodeset = cache->dbgCachedNodeset;
1713 caString = cache->dbgCachedString;
1714 caNumber = cache->dbgCachedNumber;
1715 caXSLTTree = cache->dbgCachedXSLTTree;
1716 caUndefined = cache->dbgCachedUndefined;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001717
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001718 if (cache->nodesetObjs)
1719 leftObjs -= cache->nodesetObjs->number;
1720 if (cache->stringObjs)
1721 leftObjs -= cache->stringObjs->number;
1722 if (cache->booleanObjs)
1723 leftObjs -= cache->booleanObjs->number;
1724 if (cache->numberObjs)
1725 leftObjs -= cache->numberObjs->number;
1726 if (cache->miscObjs)
1727 leftObjs -= cache->miscObjs->number;
1728 }
1729 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00001730
1731 printf("# all\n");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001732 printf("# total : %d\n", reqAll);
1733 printf("# left : %d\n", leftObjs);
1734 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
1735 printf("# reused : %d\n", reAll);
1736 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
1737
1738 printf("# node-sets\n");
1739 printf("# total : %d\n", reqNodeset);
1740 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
1741 printf("# reused : %d\n", reNodeset);
1742 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
1743
1744 printf("# strings\n");
1745 printf("# total : %d\n", reqString);
1746 printf("# created: %d\n", xmlXPathDebugObjTotalString);
1747 printf("# reused : %d\n", reString);
1748 printf("# max : %d\n", xmlXPathDebugObjMaxString);
1749
1750 printf("# booleans\n");
1751 printf("# total : %d\n", reqBool);
1752 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
1753 printf("# reused : %d\n", reBool);
1754 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
1755
1756 printf("# numbers\n");
1757 printf("# total : %d\n", reqNumber);
1758 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
1759 printf("# reused : %d\n", reNumber);
1760 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
1761
1762 printf("# XSLT result tree fragments\n");
1763 printf("# total : %d\n", reqXSLTTree);
1764 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
1765 printf("# reused : %d\n", reXSLTTree);
1766 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
1767
1768 printf("# undefined\n");
1769 printf("# total : %d\n", reqUndefined);
1770 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
1771 printf("# reused : %d\n", reUndefined);
1772 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
1773
1774}
1775
1776#endif /* XP_DEBUG_OBJ_USAGE */
1777
Daniel Veillard017b1082001-06-21 11:20:21 +00001778#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001779
1780/************************************************************************
1781 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001782 * XPath object caching *
1783 * *
1784 ************************************************************************/
1785
1786/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001787 * xmlXPathNewCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001788 *
1789 * Create a new object cache
1790 *
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001791 * Returns the xmlXPathCache just allocated.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001792 */
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001793static xmlXPathContextCachePtr
1794xmlXPathNewCache(void)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001795{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001796 xmlXPathContextCachePtr ret;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001797
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001798 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001799 if (ret == NULL) {
1800 xmlXPathErrMemory(NULL, "creating object cache\n");
1801 return(NULL);
1802 }
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001803 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001804 ret->maxNodeset = 100;
1805 ret->maxString = 100;
1806 ret->maxBoolean = 100;
1807 ret->maxNumber = 100;
1808 ret->maxMisc = 100;
1809 return(ret);
1810}
1811
1812static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001813xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001814{
1815 int i;
1816 xmlXPathObjectPtr obj;
1817
1818 if (list == NULL)
1819 return;
1820
1821 for (i = 0; i < list->number; i++) {
1822 obj = list->items[i];
1823 /*
1824 * Note that it is already assured that we don't need to
1825 * look out for namespace nodes in the node-set.
1826 */
1827 if (obj->nodesetval != NULL) {
1828 if (obj->nodesetval->nodeTab != NULL)
1829 xmlFree(obj->nodesetval->nodeTab);
1830 xmlFree(obj->nodesetval);
1831 }
1832 xmlFree(obj);
1833#ifdef XP_DEBUG_OBJ_USAGE
1834 xmlXPathDebugObjCounterAll--;
1835#endif
1836 }
1837 xmlPointerListFree(list);
1838}
1839
1840static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001841xmlXPathFreeCache(xmlXPathContextCachePtr cache)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001842{
1843 if (cache == NULL)
1844 return;
1845 if (cache->nodesetObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001846 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001847 if (cache->stringObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001848 xmlXPathCacheFreeObjectList(cache->stringObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001849 if (cache->booleanObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001850 xmlXPathCacheFreeObjectList(cache->booleanObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001851 if (cache->numberObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001852 xmlXPathCacheFreeObjectList(cache->numberObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001853 if (cache->miscObjs)
Daniel Veillard45490ae2008-07-29 09:13:19 +00001854 xmlXPathCacheFreeObjectList(cache->miscObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001855 xmlFree(cache);
1856}
1857
1858/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001859 * xmlXPathContextSetCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001860 *
1861 * @ctxt: the XPath context
1862 * @active: enables/disables (creates/frees) the cache
Daniel Veillard45490ae2008-07-29 09:13:19 +00001863 * @value: a value with semantics dependant on @options
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001864 * @options: options (currently only the value 0 is used)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001865 *
1866 * Creates/frees an object cache on the XPath context.
1867 * If activates XPath objects (xmlXPathObject) will be cached internally
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001868 * to be reused.
1869 * @options:
1870 * 0: This will set the XPath object caching:
1871 * @value:
1872 * This will set the maximum number of XPath objects
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001873 * to be cached per slot
1874 * There are 5 slots for: node-set, string, number, boolean, and
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001875 * misc objects. Use <0 for the default number (100).
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001876 * Other values for @options have currently no effect.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001877 *
1878 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1879 */
1880int
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001881xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1882 int active,
1883 int value,
1884 int options)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001885{
1886 if (ctxt == NULL)
1887 return(-1);
1888 if (active) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001889 xmlXPathContextCachePtr cache;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001890
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001891 if (ctxt->cache == NULL) {
1892 ctxt->cache = xmlXPathNewCache();
1893 if (ctxt->cache == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001894 return(-1);
1895 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001896 cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001897 if (options == 0) {
1898 if (value < 0)
1899 value = 100;
1900 cache->maxNodeset = value;
1901 cache->maxString = value;
1902 cache->maxNumber = value;
1903 cache->maxBoolean = value;
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001904 cache->maxMisc = value;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001905 }
1906 } else if (ctxt->cache != NULL) {
1907 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1908 ctxt->cache = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001909 }
1910 return(0);
1911}
1912
1913/**
1914 * xmlXPathCacheWrapNodeSet:
1915 * @ctxt: the XPath context
1916 * @val: the NodePtr value
1917 *
1918 * This is the cached version of xmlXPathWrapNodeSet().
1919 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1920 *
1921 * Returns the created or reused object.
1922 */
1923static xmlXPathObjectPtr
1924xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00001925{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001926 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1927 xmlXPathContextCachePtr cache =
1928 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001929
1930 if ((cache->miscObjs != NULL) &&
1931 (cache->miscObjs->number != 0))
1932 {
1933 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001934
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001935 ret = (xmlXPathObjectPtr)
1936 cache->miscObjs->items[--cache->miscObjs->number];
1937 ret->type = XPATH_NODESET;
1938 ret->nodesetval = val;
1939#ifdef XP_DEBUG_OBJ_USAGE
1940 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
1941#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00001942 return(ret);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001943 }
1944 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00001945
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001946 return(xmlXPathWrapNodeSet(val));
Daniel Veillard45490ae2008-07-29 09:13:19 +00001947
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001948}
1949
1950/**
1951 * xmlXPathCacheWrapString:
1952 * @ctxt: the XPath context
1953 * @val: the xmlChar * value
1954 *
1955 * This is the cached version of xmlXPathWrapString().
1956 * Wraps the @val string into an XPath object.
1957 *
1958 * Returns the created or reused object.
1959 */
1960static xmlXPathObjectPtr
1961xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00001962{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001963 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1964 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001965
1966 if ((cache->stringObjs != NULL) &&
1967 (cache->stringObjs->number != 0))
1968 {
Daniel Veillard45490ae2008-07-29 09:13:19 +00001969
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001970 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00001971
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001972 ret = (xmlXPathObjectPtr)
1973 cache->stringObjs->items[--cache->stringObjs->number];
1974 ret->type = XPATH_STRING;
1975 ret->stringval = val;
1976#ifdef XP_DEBUG_OBJ_USAGE
1977 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1978#endif
1979 return(ret);
1980 } else if ((cache->miscObjs != NULL) &&
1981 (cache->miscObjs->number != 0))
1982 {
1983 xmlXPathObjectPtr ret;
1984 /*
1985 * Fallback to misc-cache.
1986 */
1987 ret = (xmlXPathObjectPtr)
1988 cache->miscObjs->items[--cache->miscObjs->number];
1989
1990 ret->type = XPATH_STRING;
1991 ret->stringval = val;
1992#ifdef XP_DEBUG_OBJ_USAGE
1993 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1994#endif
1995 return(ret);
1996 }
1997 }
1998 return(xmlXPathWrapString(val));
1999}
2000
2001/**
2002 * xmlXPathCacheNewNodeSet:
2003 * @ctxt: the XPath context
2004 * @val: the NodePtr value
2005 *
2006 * This is the cached version of xmlXPathNewNodeSet().
2007 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2008 * it with the single Node @val
2009 *
2010 * Returns the created or reused object.
2011 */
2012static xmlXPathObjectPtr
2013xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2014{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002015 if ((ctxt != NULL) && (ctxt->cache)) {
2016 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002017
2018 if ((cache->nodesetObjs != NULL) &&
2019 (cache->nodesetObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002020 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002021 xmlXPathObjectPtr ret;
2022 /*
2023 * Use the nodset-cache.
Daniel Veillard45490ae2008-07-29 09:13:19 +00002024 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002025 ret = (xmlXPathObjectPtr)
2026 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2027 ret->type = XPATH_NODESET;
2028 ret->boolval = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002029 if (val) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002030 if ((ret->nodesetval->nodeMax == 0) ||
2031 (val->type == XML_NAMESPACE_DECL))
2032 {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002033 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002034 } else {
2035 ret->nodesetval->nodeTab[0] = val;
2036 ret->nodesetval->nodeNr = 1;
2037 }
2038 }
2039#ifdef XP_DEBUG_OBJ_USAGE
2040 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2041#endif
2042 return(ret);
2043 } else if ((cache->miscObjs != NULL) &&
2044 (cache->miscObjs->number != 0))
2045 {
2046 xmlXPathObjectPtr ret;
2047 /*
2048 * Fallback to misc-cache.
2049 */
2050
2051 ret = (xmlXPathObjectPtr)
2052 cache->miscObjs->items[--cache->miscObjs->number];
2053
2054 ret->type = XPATH_NODESET;
2055 ret->boolval = 0;
2056 ret->nodesetval = xmlXPathNodeSetCreate(val);
2057#ifdef XP_DEBUG_OBJ_USAGE
2058 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2059#endif
2060 return(ret);
2061 }
2062 }
2063 return(xmlXPathNewNodeSet(val));
2064}
2065
2066/**
2067 * xmlXPathCacheNewCString:
2068 * @ctxt: the XPath context
2069 * @val: the char * value
2070 *
2071 * This is the cached version of xmlXPathNewCString().
2072 * Acquire an xmlXPathObjectPtr of type string and of value @val
2073 *
2074 * Returns the created or reused object.
2075 */
2076static xmlXPathObjectPtr
2077xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002078{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002079 if ((ctxt != NULL) && (ctxt->cache)) {
2080 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002081
2082 if ((cache->stringObjs != NULL) &&
2083 (cache->stringObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002084 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002085 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002086
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002087 ret = (xmlXPathObjectPtr)
2088 cache->stringObjs->items[--cache->stringObjs->number];
2089
2090 ret->type = XPATH_STRING;
2091 ret->stringval = xmlStrdup(BAD_CAST val);
2092#ifdef XP_DEBUG_OBJ_USAGE
2093 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2094#endif
2095 return(ret);
2096 } else if ((cache->miscObjs != NULL) &&
2097 (cache->miscObjs->number != 0))
2098 {
2099 xmlXPathObjectPtr ret;
2100
2101 ret = (xmlXPathObjectPtr)
2102 cache->miscObjs->items[--cache->miscObjs->number];
2103
2104 ret->type = XPATH_STRING;
2105 ret->stringval = xmlStrdup(BAD_CAST val);
2106#ifdef XP_DEBUG_OBJ_USAGE
2107 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2108#endif
2109 return(ret);
2110 }
2111 }
2112 return(xmlXPathNewCString(val));
2113}
2114
2115/**
2116 * xmlXPathCacheNewString:
2117 * @ctxt: the XPath context
2118 * @val: the xmlChar * value
2119 *
2120 * This is the cached version of xmlXPathNewString().
2121 * Acquire an xmlXPathObjectPtr of type string and of value @val
2122 *
2123 * Returns the created or reused object.
2124 */
2125static xmlXPathObjectPtr
2126xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002127{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002128 if ((ctxt != NULL) && (ctxt->cache)) {
2129 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002130
2131 if ((cache->stringObjs != NULL) &&
2132 (cache->stringObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002133 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002134 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002135
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002136 ret = (xmlXPathObjectPtr)
2137 cache->stringObjs->items[--cache->stringObjs->number];
2138 ret->type = XPATH_STRING;
2139 if (val != NULL)
2140 ret->stringval = xmlStrdup(val);
2141 else
2142 ret->stringval = xmlStrdup((const xmlChar *)"");
2143#ifdef XP_DEBUG_OBJ_USAGE
2144 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2145#endif
2146 return(ret);
2147 } else if ((cache->miscObjs != NULL) &&
2148 (cache->miscObjs->number != 0))
2149 {
2150 xmlXPathObjectPtr ret;
2151
2152 ret = (xmlXPathObjectPtr)
2153 cache->miscObjs->items[--cache->miscObjs->number];
2154
2155 ret->type = XPATH_STRING;
2156 if (val != NULL)
2157 ret->stringval = xmlStrdup(val);
2158 else
2159 ret->stringval = xmlStrdup((const xmlChar *)"");
2160#ifdef XP_DEBUG_OBJ_USAGE
2161 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2162#endif
2163 return(ret);
2164 }
2165 }
2166 return(xmlXPathNewString(val));
2167}
2168
2169/**
2170 * xmlXPathCacheNewBoolean:
2171 * @ctxt: the XPath context
2172 * @val: the boolean value
2173 *
2174 * This is the cached version of xmlXPathNewBoolean().
2175 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2176 *
2177 * Returns the created or reused object.
2178 */
2179static xmlXPathObjectPtr
2180xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
Daniel Veillard45490ae2008-07-29 09:13:19 +00002181{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002182 if ((ctxt != NULL) && (ctxt->cache)) {
2183 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002184
2185 if ((cache->booleanObjs != NULL) &&
2186 (cache->booleanObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002187 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002188 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002189
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002190 ret = (xmlXPathObjectPtr)
2191 cache->booleanObjs->items[--cache->booleanObjs->number];
2192 ret->type = XPATH_BOOLEAN;
2193 ret->boolval = (val != 0);
2194#ifdef XP_DEBUG_OBJ_USAGE
2195 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2196#endif
2197 return(ret);
2198 } else if ((cache->miscObjs != NULL) &&
2199 (cache->miscObjs->number != 0))
2200 {
2201 xmlXPathObjectPtr ret;
2202
2203 ret = (xmlXPathObjectPtr)
2204 cache->miscObjs->items[--cache->miscObjs->number];
2205
2206 ret->type = XPATH_BOOLEAN;
2207 ret->boolval = (val != 0);
2208#ifdef XP_DEBUG_OBJ_USAGE
2209 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2210#endif
2211 return(ret);
2212 }
2213 }
2214 return(xmlXPathNewBoolean(val));
2215}
2216
2217/**
2218 * xmlXPathCacheNewFloat:
2219 * @ctxt: the XPath context
2220 * @val: the double value
2221 *
2222 * This is the cached version of xmlXPathNewFloat().
2223 * Acquires an xmlXPathObjectPtr of type double and of value @val
2224 *
2225 * Returns the created or reused object.
2226 */
2227static xmlXPathObjectPtr
2228xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2229{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002230 if ((ctxt != NULL) && (ctxt->cache)) {
2231 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002232
2233 if ((cache->numberObjs != NULL) &&
2234 (cache->numberObjs->number != 0))
Daniel Veillard45490ae2008-07-29 09:13:19 +00002235 {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002236 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002237
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002238 ret = (xmlXPathObjectPtr)
2239 cache->numberObjs->items[--cache->numberObjs->number];
2240 ret->type = XPATH_NUMBER;
2241 ret->floatval = val;
2242#ifdef XP_DEBUG_OBJ_USAGE
2243 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2244#endif
2245 return(ret);
2246 } else if ((cache->miscObjs != NULL) &&
2247 (cache->miscObjs->number != 0))
2248 {
2249 xmlXPathObjectPtr ret;
2250
2251 ret = (xmlXPathObjectPtr)
2252 cache->miscObjs->items[--cache->miscObjs->number];
2253
2254 ret->type = XPATH_NUMBER;
2255 ret->floatval = val;
2256#ifdef XP_DEBUG_OBJ_USAGE
2257 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2258#endif
2259 return(ret);
2260 }
2261 }
2262 return(xmlXPathNewFloat(val));
2263}
2264
2265/**
2266 * xmlXPathCacheConvertString:
2267 * @ctxt: the XPath context
2268 * @val: an XPath object
2269 *
2270 * This is the cached version of xmlXPathConvertString().
2271 * Converts an existing object to its string() equivalent
2272 *
2273 * Returns a created or reused object, the old one is freed (cached)
2274 * (or the operation is done directly on @val)
2275 */
2276
2277static xmlXPathObjectPtr
2278xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00002279 xmlChar *res = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002280
2281 if (val == NULL)
2282 return(xmlXPathCacheNewCString(ctxt, ""));
2283
2284 switch (val->type) {
2285 case XPATH_UNDEFINED:
2286#ifdef DEBUG_EXPR
2287 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2288#endif
2289 break;
2290 case XPATH_NODESET:
2291 case XPATH_XSLT_TREE:
2292 res = xmlXPathCastNodeSetToString(val->nodesetval);
2293 break;
2294 case XPATH_STRING:
2295 return(val);
2296 case XPATH_BOOLEAN:
2297 res = xmlXPathCastBooleanToString(val->boolval);
2298 break;
2299 case XPATH_NUMBER:
2300 res = xmlXPathCastNumberToString(val->floatval);
2301 break;
2302 case XPATH_USERS:
2303 case XPATH_POINT:
2304 case XPATH_RANGE:
2305 case XPATH_LOCATIONSET:
2306 TODO;
2307 break;
2308 }
2309 xmlXPathReleaseObject(ctxt, val);
2310 if (res == NULL)
2311 return(xmlXPathCacheNewCString(ctxt, ""));
2312 return(xmlXPathCacheWrapString(ctxt, res));
2313}
2314
2315/**
2316 * xmlXPathCacheObjectCopy:
2317 * @ctxt: the XPath context
2318 * @val: the original object
2319 *
2320 * This is the cached version of xmlXPathObjectCopy().
2321 * Acquire a copy of a given object
2322 *
2323 * Returns a created or reused created object.
2324 */
2325static xmlXPathObjectPtr
2326xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2327{
2328 if (val == NULL)
2329 return(NULL);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002330
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002331 if (XP_HAS_CACHE(ctxt)) {
2332 switch (val->type) {
2333 case XPATH_NODESET:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002334 return(xmlXPathCacheWrapNodeSet(ctxt,
2335 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002336 case XPATH_STRING:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002337 return(xmlXPathCacheNewString(ctxt, val->stringval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002338 case XPATH_BOOLEAN:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002339 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002340 case XPATH_NUMBER:
2341 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2342 default:
2343 break;
2344 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002345 }
2346 return(xmlXPathObjectCopy(val));
2347}
2348
2349/**
2350 * xmlXPathCacheConvertBoolean:
2351 * @ctxt: the XPath context
2352 * @val: an XPath object
2353 *
2354 * This is the cached version of xmlXPathConvertBoolean().
2355 * Converts an existing object to its boolean() equivalent
2356 *
2357 * Returns a created or reused object, the old one is freed (or the operation
2358 * is done directly on @val)
2359 */
2360static xmlXPathObjectPtr
2361xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2362 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002363
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002364 if (val == NULL)
2365 return(xmlXPathCacheNewBoolean(ctxt, 0));
2366 if (val->type == XPATH_BOOLEAN)
2367 return(val);
2368 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2369 xmlXPathReleaseObject(ctxt, val);
2370 return(ret);
2371}
2372
2373/**
2374 * xmlXPathCacheConvertNumber:
2375 * @ctxt: the XPath context
2376 * @val: an XPath object
2377 *
2378 * This is the cached version of xmlXPathConvertNumber().
2379 * Converts an existing object to its number() equivalent
2380 *
2381 * Returns a created or reused object, the old one is freed (or the operation
2382 * is done directly on @val)
2383 */
2384static xmlXPathObjectPtr
2385xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2386 xmlXPathObjectPtr ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00002387
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002388 if (val == NULL)
2389 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2390 if (val->type == XPATH_NUMBER)
2391 return(val);
2392 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2393 xmlXPathReleaseObject(ctxt, val);
2394 return(ret);
2395}
2396
2397/************************************************************************
2398 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +00002399 * Parser stacks related functions and macros *
Owen Taylor3473f882001-02-23 17:55:21 +00002400 * *
2401 ************************************************************************/
2402
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002403/**
Daniel Veillardf5048b32011-08-18 17:10:13 +08002404 * xmlXPathSetFrame:
2405 * @ctxt: an XPath parser context
2406 *
2407 * Set the callee evaluation frame
2408 *
2409 * Returns the previous frame value to be restored once done
2410 */
2411static int
2412xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2413 int ret;
2414
2415 if (ctxt == NULL)
2416 return(0);
2417 ret = ctxt->valueFrame;
2418 ctxt->valueFrame = ctxt->valueNr;
2419 return(ret);
2420}
2421
2422/**
2423 * xmlXPathPopFrame:
2424 * @ctxt: an XPath parser context
2425 * @frame: the previous frame value
2426 *
2427 * Remove the callee evaluation frame
2428 */
2429static void
2430xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2431 if (ctxt == NULL)
2432 return;
2433 if (ctxt->valueNr < ctxt->valueFrame) {
2434 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2435 }
2436 ctxt->valueFrame = frame;
2437}
2438
2439/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002440 * valuePop:
2441 * @ctxt: an XPath evaluation context
2442 *
2443 * Pops the top XPath object from the value stack
2444 *
2445 * Returns the XPath object just removed
2446 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002447xmlXPathObjectPtr
Daniel Veillard1c732d22002-11-30 11:22:59 +00002448valuePop(xmlXPathParserContextPtr ctxt)
2449{
2450 xmlXPathObjectPtr ret;
2451
Daniel Veillarda82b1822004-11-08 16:24:57 +00002452 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
Daniel Veillard24505b02005-07-28 23:49:35 +00002453 return (NULL);
Daniel Veillardf5048b32011-08-18 17:10:13 +08002454
2455 if (ctxt->valueNr <= ctxt->valueFrame) {
2456 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2457 return (NULL);
2458 }
2459
Daniel Veillard1c732d22002-11-30 11:22:59 +00002460 ctxt->valueNr--;
2461 if (ctxt->valueNr > 0)
2462 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2463 else
2464 ctxt->value = NULL;
2465 ret = ctxt->valueTab[ctxt->valueNr];
Daniel Veillard24505b02005-07-28 23:49:35 +00002466 ctxt->valueTab[ctxt->valueNr] = NULL;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002467 return (ret);
2468}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002469/**
2470 * valuePush:
2471 * @ctxt: an XPath evaluation context
2472 * @value: the XPath object
2473 *
2474 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002475 *
2476 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002477 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002478int
Daniel Veillard1c732d22002-11-30 11:22:59 +00002479valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2480{
Daniel Veillarda82b1822004-11-08 16:24:57 +00002481 if ((ctxt == NULL) || (value == NULL)) return(-1);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002482 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002483 xmlXPathObjectPtr *tmp;
2484
2485 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2486 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00002487 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002488 if (tmp == NULL) {
Daniel Veillard1c732d22002-11-30 11:22:59 +00002489 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08002490 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002491 return (0);
2492 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002493 ctxt->valueMax *= 2;
2494 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002495 }
2496 ctxt->valueTab[ctxt->valueNr] = value;
2497 ctxt->value = value;
2498 return (ctxt->valueNr++);
2499}
Owen Taylor3473f882001-02-23 17:55:21 +00002500
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002501/**
2502 * xmlXPathPopBoolean:
2503 * @ctxt: an XPath parser context
2504 *
2505 * Pops a boolean from the stack, handling conversion if needed.
2506 * Check error with #xmlXPathCheckError.
2507 *
2508 * Returns the boolean
2509 */
2510int
2511xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2512 xmlXPathObjectPtr obj;
2513 int ret;
2514
2515 obj = valuePop(ctxt);
2516 if (obj == NULL) {
2517 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2518 return(0);
2519 }
William M. Brack08171912003-12-29 02:52:11 +00002520 if (obj->type != XPATH_BOOLEAN)
2521 ret = xmlXPathCastToBoolean(obj);
2522 else
2523 ret = obj->boolval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002524 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002525 return(ret);
2526}
2527
2528/**
2529 * xmlXPathPopNumber:
2530 * @ctxt: an XPath parser context
2531 *
2532 * Pops a number from the stack, handling conversion if needed.
2533 * Check error with #xmlXPathCheckError.
2534 *
2535 * Returns the number
2536 */
2537double
2538xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2539 xmlXPathObjectPtr obj;
2540 double ret;
2541
2542 obj = valuePop(ctxt);
2543 if (obj == NULL) {
2544 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2545 return(0);
2546 }
William M. Brack08171912003-12-29 02:52:11 +00002547 if (obj->type != XPATH_NUMBER)
2548 ret = xmlXPathCastToNumber(obj);
2549 else
2550 ret = obj->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002551 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002552 return(ret);
2553}
2554
2555/**
2556 * xmlXPathPopString:
2557 * @ctxt: an XPath parser context
2558 *
2559 * Pops a string from the stack, handling conversion if needed.
2560 * Check error with #xmlXPathCheckError.
2561 *
2562 * Returns the string
2563 */
2564xmlChar *
2565xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2566 xmlXPathObjectPtr obj;
2567 xmlChar * ret;
2568
2569 obj = valuePop(ctxt);
2570 if (obj == NULL) {
2571 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2572 return(NULL);
2573 }
William M. Brack08171912003-12-29 02:52:11 +00002574 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002575 /* TODO: needs refactoring somewhere else */
2576 if (obj->stringval == ret)
2577 obj->stringval = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002578 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002579 return(ret);
2580}
2581
2582/**
2583 * xmlXPathPopNodeSet:
2584 * @ctxt: an XPath parser context
2585 *
2586 * Pops a node-set from the stack, handling conversion if needed.
2587 * Check error with #xmlXPathCheckError.
2588 *
2589 * Returns the node-set
2590 */
2591xmlNodeSetPtr
2592xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2593 xmlXPathObjectPtr obj;
2594 xmlNodeSetPtr ret;
2595
Daniel Veillardf2a36f92004-11-08 17:55:01 +00002596 if (ctxt == NULL) return(NULL);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002597 if (ctxt->value == NULL) {
2598 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2599 return(NULL);
2600 }
2601 if (!xmlXPathStackIsNodeSet(ctxt)) {
2602 xmlXPathSetTypeError(ctxt);
2603 return(NULL);
2604 }
2605 obj = valuePop(ctxt);
2606 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00002607#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00002608 /* to fix memory leak of not clearing obj->user */
2609 if (obj->boolval && obj->user != NULL)
2610 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00002611#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002612 obj->nodesetval = NULL;
2613 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002614 return(ret);
2615}
2616
2617/**
2618 * xmlXPathPopExternal:
2619 * @ctxt: an XPath parser context
2620 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002621 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002622 * Check error with #xmlXPathCheckError.
2623 *
2624 * Returns the object
2625 */
2626void *
2627xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2628 xmlXPathObjectPtr obj;
2629 void * ret;
2630
Daniel Veillarda82b1822004-11-08 16:24:57 +00002631 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002632 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2633 return(NULL);
2634 }
2635 if (ctxt->value->type != XPATH_USERS) {
2636 xmlXPathSetTypeError(ctxt);
2637 return(NULL);
2638 }
2639 obj = valuePop(ctxt);
2640 ret = obj->user;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002641 obj->user = NULL;
2642 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002643 return(ret);
2644}
2645
Owen Taylor3473f882001-02-23 17:55:21 +00002646/*
2647 * Macros for accessing the content. Those should be used only by the parser,
2648 * and not exported.
2649 *
2650 * Dirty macros, i.e. one need to make assumption on the context to use them
2651 *
2652 * CUR_PTR return the current pointer to the xmlChar to be parsed.
2653 * CUR returns the current xmlChar value, i.e. a 8 bit value
2654 * in ISO-Latin or UTF-8.
2655 * This should be used internally by the parser
2656 * only to compare to ASCII values otherwise it would break when
2657 * running with UTF-8 encoding.
2658 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
2659 * to compare on ASCII based substring.
2660 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2661 * strings within the parser.
2662 * CURRENT Returns the current char value, with the full decoding of
2663 * UTF-8 if we are using this mode. It returns an int.
2664 * NEXT Skip to the next character, this does the proper decoding
2665 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
2666 * It returns the pointer to the current xmlChar.
2667 */
2668
2669#define CUR (*ctxt->cur)
2670#define SKIP(val) ctxt->cur += (val)
2671#define NXT(val) ctxt->cur[(val)]
2672#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00002673#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2674
2675#define COPY_BUF(l,b,i,v) \
2676 if (l == 1) b[i++] = (xmlChar) v; \
2677 else i += xmlCopyChar(l,&b[i],v)
2678
2679#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00002680
Daniel Veillard45490ae2008-07-29 09:13:19 +00002681#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00002682 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00002683
2684#define CURRENT (*ctxt->cur)
2685#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
2686
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002687
2688#ifndef DBL_DIG
2689#define DBL_DIG 16
2690#endif
2691#ifndef DBL_EPSILON
2692#define DBL_EPSILON 1E-9
2693#endif
2694
2695#define UPPER_DOUBLE 1E9
2696#define LOWER_DOUBLE 1E-5
William M. Brackca797882007-05-11 14:45:53 +00002697#define LOWER_DOUBLE_EXP 5
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002698
2699#define INTEGER_DIGITS DBL_DIG
William M. Brackca797882007-05-11 14:45:53 +00002700#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002701#define EXPONENT_DIGITS (3 + 2)
2702
2703/**
2704 * xmlXPathFormatNumber:
2705 * @number: number to format
2706 * @buffer: output buffer
2707 * @buffersize: size of output buffer
2708 *
2709 * Convert the number into a string representation.
2710 */
2711static void
2712xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2713{
Daniel Veillardcda96922001-08-21 10:56:31 +00002714 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002715 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00002716 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002717 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002718 break;
2719 case -1:
2720 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002721 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002722 break;
2723 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00002724 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002725 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002726 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00002727 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002728 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002729 } else if (number == ((int) number)) {
2730 char work[30];
2731 char *ptr, *cur;
Daniel Veillardb3d14912005-09-04 20:47:39 +00002732 int value = (int) number;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002733
2734 ptr = &buffer[0];
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002735 if (value == 0) {
2736 *ptr++ = '0';
2737 } else {
Daniel Veillardb3d14912005-09-04 20:47:39 +00002738 snprintf(work, 29, "%d", value);
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002739 cur = &work[0];
Daniel Veillardb3d14912005-09-04 20:47:39 +00002740 while ((*cur) && (ptr - buffer < buffersize)) {
2741 *ptr++ = *cur++;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002742 }
2743 }
2744 if (ptr - buffer < buffersize) {
2745 *ptr = 0;
2746 } else if (buffersize > 0) {
2747 ptr--;
2748 *ptr = 0;
2749 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002750 } else {
William M. Brackca797882007-05-11 14:45:53 +00002751 /*
2752 For the dimension of work,
2753 DBL_DIG is number of significant digits
2754 EXPONENT is only needed for "scientific notation"
2755 3 is sign, decimal point, and terminating zero
2756 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2757 Note that this dimension is slightly (a few characters)
2758 larger than actually necessary.
2759 */
2760 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
Bjorn Reese70a9da52001-04-21 16:57:29 +00002761 int integer_place, fraction_place;
2762 char *ptr;
2763 char *after_fraction;
2764 double absolute_value;
2765 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002766
Bjorn Reese70a9da52001-04-21 16:57:29 +00002767 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002768
Bjorn Reese70a9da52001-04-21 16:57:29 +00002769 /*
2770 * First choose format - scientific or regular floating point.
2771 * In either case, result is in work, and after_fraction points
2772 * just past the fractional part.
2773 */
2774 if ( ((absolute_value > UPPER_DOUBLE) ||
2775 (absolute_value < LOWER_DOUBLE)) &&
2776 (absolute_value != 0.0) ) {
2777 /* Use scientific notation */
2778 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2779 fraction_place = DBL_DIG - 1;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002780 size = snprintf(work, sizeof(work),"%*.*e",
Bjorn Reese70a9da52001-04-21 16:57:29 +00002781 integer_place, fraction_place, number);
Daniel Veillard11ce4002006-03-10 00:36:23 +00002782 while ((size > 0) && (work[size] != 'e')) size--;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002783
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002784 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002785 else {
2786 /* Use regular notation */
William M. Brackca797882007-05-11 14:45:53 +00002787 if (absolute_value > 0.0) {
2788 integer_place = (int)log10(absolute_value);
2789 if (integer_place > 0)
2790 fraction_place = DBL_DIG - integer_place - 1;
2791 else
2792 fraction_place = DBL_DIG - integer_place;
2793 } else {
2794 fraction_place = 1;
2795 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002796 size = snprintf(work, sizeof(work), "%0.*f",
2797 fraction_place, number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002798 }
2799
Bjorn Reese70a9da52001-04-21 16:57:29 +00002800 /* Remove fractional trailing zeroes */
William M. Brackca797882007-05-11 14:45:53 +00002801 after_fraction = work + size;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002802 ptr = after_fraction;
2803 while (*(--ptr) == '0')
2804 ;
2805 if (*ptr != '.')
2806 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002807 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002808
2809 /* Finally copy result back to caller */
2810 size = strlen(work) + 1;
2811 if (size > buffersize) {
2812 work[buffersize - 1] = 0;
2813 size = buffersize;
2814 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002815 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002816 }
2817 break;
2818 }
2819}
2820
Owen Taylor3473f882001-02-23 17:55:21 +00002821
2822/************************************************************************
2823 * *
2824 * Routines to handle NodeSets *
2825 * *
2826 ************************************************************************/
2827
2828/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002829 * xmlXPathOrderDocElems:
2830 * @doc: an input document
2831 *
2832 * Call this routine to speed up XPath computation on static documents.
2833 * This stamps all the element nodes with the document order
2834 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00002835 * field, the value stored is actually - the node number (starting at -1)
2836 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002837 *
William M. Brack08171912003-12-29 02:52:11 +00002838 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002839 * of error.
2840 */
2841long
2842xmlXPathOrderDocElems(xmlDocPtr doc) {
2843 long count = 0;
2844 xmlNodePtr cur;
2845
2846 if (doc == NULL)
2847 return(-1);
2848 cur = doc->children;
2849 while (cur != NULL) {
2850 if (cur->type == XML_ELEMENT_NODE) {
2851 cur->content = (void *) (-(++count));
2852 if (cur->children != NULL) {
2853 cur = cur->children;
2854 continue;
2855 }
2856 }
2857 if (cur->next != NULL) {
2858 cur = cur->next;
2859 continue;
2860 }
2861 do {
2862 cur = cur->parent;
2863 if (cur == NULL)
2864 break;
2865 if (cur == (xmlNodePtr) doc) {
2866 cur = NULL;
2867 break;
2868 }
2869 if (cur->next != NULL) {
2870 cur = cur->next;
2871 break;
2872 }
2873 } while (cur != NULL);
2874 }
2875 return(count);
2876}
2877
2878/**
Owen Taylor3473f882001-02-23 17:55:21 +00002879 * xmlXPathCmpNodes:
2880 * @node1: the first node
2881 * @node2: the second node
2882 *
2883 * Compare two nodes w.r.t document order
2884 *
2885 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00002886 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00002887 */
2888int
2889xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2890 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002891 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002892 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002893 xmlNodePtr cur, root;
2894
2895 if ((node1 == NULL) || (node2 == NULL))
2896 return(-2);
2897 /*
2898 * a couple of optimizations which will avoid computations in most cases
2899 */
William M. Brackee0b9822007-03-07 08:15:01 +00002900 if (node1 == node2) /* trivial case */
2901 return(0);
Daniel Veillardedfd5882003-03-07 14:20:40 +00002902 if (node1->type == XML_ATTRIBUTE_NODE) {
2903 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002904 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002905 node1 = node1->parent;
2906 }
2907 if (node2->type == XML_ATTRIBUTE_NODE) {
2908 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002909 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002910 node2 = node2->parent;
2911 }
2912 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00002913 if (attr1 == attr2) {
2914 /* not required, but we keep attributes in order */
2915 if (attr1 != 0) {
2916 cur = attrNode2->prev;
2917 while (cur != NULL) {
2918 if (cur == attrNode1)
2919 return (1);
2920 cur = cur->prev;
2921 }
2922 return (-1);
2923 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00002924 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00002925 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00002926 if (attr2 == 1)
2927 return(1);
2928 return(-1);
2929 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002930 if ((node1->type == XML_NAMESPACE_DECL) ||
2931 (node2->type == XML_NAMESPACE_DECL))
2932 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00002933 if (node1 == node2->prev)
2934 return(1);
2935 if (node1 == node2->next)
2936 return(-1);
2937
2938 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002939 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002940 */
2941 if ((node1->type == XML_ELEMENT_NODE) &&
2942 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002943 (0 > (long) node1->content) &&
2944 (0 > (long) node2->content) &&
2945 (node1->doc == node2->doc)) {
2946 long l1, l2;
2947
2948 l1 = -((long) node1->content);
2949 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002950 if (l1 < l2)
2951 return(1);
2952 if (l1 > l2)
2953 return(-1);
2954 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002955
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002956 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002957 * compute depth to root
2958 */
2959 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2960 if (cur == node1)
2961 return(1);
2962 depth2++;
2963 }
2964 root = cur;
2965 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2966 if (cur == node2)
2967 return(-1);
2968 depth1++;
2969 }
2970 /*
2971 * Distinct document (or distinct entities :-( ) case.
2972 */
2973 if (root != cur) {
2974 return(-2);
2975 }
2976 /*
2977 * get the nearest common ancestor.
2978 */
2979 while (depth1 > depth2) {
2980 depth1--;
2981 node1 = node1->parent;
2982 }
2983 while (depth2 > depth1) {
2984 depth2--;
2985 node2 = node2->parent;
2986 }
2987 while (node1->parent != node2->parent) {
2988 node1 = node1->parent;
2989 node2 = node2->parent;
2990 /* should not happen but just in case ... */
2991 if ((node1 == NULL) || (node2 == NULL))
2992 return(-2);
2993 }
2994 /*
2995 * Find who's first.
2996 */
Daniel Veillardf49be472004-02-17 11:48:18 +00002997 if (node1 == node2->prev)
2998 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00002999 if (node1 == node2->next)
3000 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00003001 /*
3002 * Speedup using document order if availble.
3003 */
3004 if ((node1->type == XML_ELEMENT_NODE) &&
3005 (node2->type == XML_ELEMENT_NODE) &&
3006 (0 > (long) node1->content) &&
3007 (0 > (long) node2->content) &&
3008 (node1->doc == node2->doc)) {
3009 long l1, l2;
3010
3011 l1 = -((long) node1->content);
3012 l2 = -((long) node2->content);
3013 if (l1 < l2)
3014 return(1);
3015 if (l1 > l2)
3016 return(-1);
3017 }
3018
Owen Taylor3473f882001-02-23 17:55:21 +00003019 for (cur = node1->next;cur != NULL;cur = cur->next)
3020 if (cur == node2)
3021 return(1);
3022 return(-1); /* assume there is no sibling list corruption */
3023}
3024
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003025#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003026/**
3027 * xmlXPathCmpNodesExt:
3028 * @node1: the first node
3029 * @node2: the second node
3030 *
3031 * Compare two nodes w.r.t document order.
3032 * This one is optimized for handling of non-element nodes.
3033 *
3034 * Returns -2 in case of error 1 if first point < second point, 0 if
3035 * it's the same node, -1 otherwise
3036 */
3037static int
3038xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
3039 int depth1, depth2;
3040 int misc = 0, precedence1 = 0, precedence2 = 0;
3041 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
3042 xmlNodePtr cur, root;
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003043 long l1, l2;
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003044
3045 if ((node1 == NULL) || (node2 == NULL))
3046 return(-2);
3047
3048 if (node1 == node2)
3049 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00003050
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003051 /*
3052 * a couple of optimizations which will avoid computations in most cases
Daniel Veillard45490ae2008-07-29 09:13:19 +00003053 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003054 switch (node1->type) {
3055 case XML_ELEMENT_NODE:
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003056 if (node2->type == XML_ELEMENT_NODE) {
3057 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
3058 (0 > (long) node2->content) &&
3059 (node1->doc == node2->doc))
Daniel Veillard45490ae2008-07-29 09:13:19 +00003060 {
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003061 l1 = -((long) node1->content);
3062 l2 = -((long) node2->content);
3063 if (l1 < l2)
3064 return(1);
3065 if (l1 > l2)
3066 return(-1);
3067 } else
Daniel Veillard45490ae2008-07-29 09:13:19 +00003068 goto turtle_comparison;
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003069 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003070 break;
3071 case XML_ATTRIBUTE_NODE:
3072 precedence1 = 1; /* element is owner */
3073 miscNode1 = node1;
3074 node1 = node1->parent;
3075 misc = 1;
3076 break;
3077 case XML_TEXT_NODE:
3078 case XML_CDATA_SECTION_NODE:
3079 case XML_COMMENT_NODE:
3080 case XML_PI_NODE: {
3081 miscNode1 = node1;
3082 /*
3083 * Find nearest element node.
Daniel Veillard45490ae2008-07-29 09:13:19 +00003084 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003085 if (node1->prev != NULL) {
3086 do {
3087 node1 = node1->prev;
3088 if (node1->type == XML_ELEMENT_NODE) {
3089 precedence1 = 3; /* element in prev-sibl axis */
3090 break;
3091 }
3092 if (node1->prev == NULL) {
3093 precedence1 = 2; /* element is parent */
3094 /*
3095 * URGENT TODO: Are there any cases, where the
3096 * parent of such a node is not an element node?
3097 */
3098 node1 = node1->parent;
3099 break;
3100 }
3101 } while (1);
3102 } else {
3103 precedence1 = 2; /* element is parent */
3104 node1 = node1->parent;
3105 }
William M. Brack31700e62007-06-13 20:33:02 +00003106 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
3107 (0 <= (long) node1->content)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003108 /*
3109 * Fallback for whatever case.
3110 */
3111 node1 = miscNode1;
3112 precedence1 = 0;
3113 } else
3114 misc = 1;
3115 }
3116 break;
3117 case XML_NAMESPACE_DECL:
3118 /*
3119 * TODO: why do we return 1 for namespace nodes?
3120 */
3121 return(1);
3122 default:
3123 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00003124 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003125 switch (node2->type) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00003126 case XML_ELEMENT_NODE:
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003127 break;
3128 case XML_ATTRIBUTE_NODE:
3129 precedence2 = 1; /* element is owner */
3130 miscNode2 = node2;
3131 node2 = node2->parent;
3132 misc = 1;
3133 break;
3134 case XML_TEXT_NODE:
3135 case XML_CDATA_SECTION_NODE:
3136 case XML_COMMENT_NODE:
3137 case XML_PI_NODE: {
3138 miscNode2 = node2;
3139 if (node2->prev != NULL) {
3140 do {
3141 node2 = node2->prev;
3142 if (node2->type == XML_ELEMENT_NODE) {
3143 precedence2 = 3; /* element in prev-sibl axis */
3144 break;
3145 }
3146 if (node2->prev == NULL) {
3147 precedence2 = 2; /* element is parent */
3148 node2 = node2->parent;
3149 break;
3150 }
3151 } while (1);
3152 } else {
3153 precedence2 = 2; /* element is parent */
3154 node2 = node2->parent;
Daniel Veillard45490ae2008-07-29 09:13:19 +00003155 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003156 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3157 (0 <= (long) node1->content))
3158 {
3159 node2 = miscNode2;
3160 precedence2 = 0;
3161 } else
3162 misc = 1;
3163 }
3164 break;
3165 case XML_NAMESPACE_DECL:
3166 return(1);
3167 default:
3168 break;
3169 }
3170 if (misc) {
3171 if (node1 == node2) {
3172 if (precedence1 == precedence2) {
3173 /*
3174 * The ugly case; but normally there aren't many
3175 * adjacent non-element nodes around.
3176 */
3177 cur = miscNode2->prev;
3178 while (cur != NULL) {
3179 if (cur == miscNode1)
3180 return(1);
3181 if (cur->type == XML_ELEMENT_NODE)
3182 return(-1);
3183 cur = cur->prev;
3184 }
3185 return (-1);
3186 } else {
3187 /*
3188 * Evaluate based on higher precedence wrt to the element.
3189 * TODO: This assumes attributes are sorted before content.
3190 * Is this 100% correct?
3191 */
3192 if (precedence1 < precedence2)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003193 return(1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003194 else
Daniel Veillard45490ae2008-07-29 09:13:19 +00003195 return(-1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003196 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00003197 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003198 /*
3199 * Special case: One of the helper-elements is contained by the other.
3200 * <foo>
3201 * <node2>
3202 * <node1>Text-1(precedence1 == 2)</node1>
3203 * </node2>
3204 * Text-6(precedence2 == 3)
3205 * </foo>
Daniel Veillard45490ae2008-07-29 09:13:19 +00003206 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003207 if ((precedence2 == 3) && (precedence1 > 1)) {
3208 cur = node1->parent;
3209 while (cur) {
3210 if (cur == node2)
3211 return(1);
3212 cur = cur->parent;
3213 }
3214 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00003215 if ((precedence1 == 3) && (precedence2 > 1)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003216 cur = node2->parent;
3217 while (cur) {
3218 if (cur == node1)
3219 return(-1);
3220 cur = cur->parent;
3221 }
3222 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00003223 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003224
3225 /*
3226 * Speedup using document order if availble.
3227 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00003228 if ((node1->type == XML_ELEMENT_NODE) &&
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003229 (node2->type == XML_ELEMENT_NODE) &&
3230 (0 > (long) node1->content) &&
3231 (0 > (long) node2->content) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +00003232 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003233
3234 l1 = -((long) node1->content);
3235 l2 = -((long) node2->content);
3236 if (l1 < l2)
3237 return(1);
3238 if (l1 > l2)
3239 return(-1);
3240 }
3241
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003242turtle_comparison:
3243
3244 if (node1 == node2->prev)
3245 return(1);
3246 if (node1 == node2->next)
3247 return(-1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003248 /*
3249 * compute depth to root
3250 */
3251 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3252 if (cur == node1)
3253 return(1);
3254 depth2++;
3255 }
3256 root = cur;
3257 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3258 if (cur == node2)
3259 return(-1);
3260 depth1++;
3261 }
3262 /*
3263 * Distinct document (or distinct entities :-( ) case.
3264 */
3265 if (root != cur) {
3266 return(-2);
3267 }
3268 /*
3269 * get the nearest common ancestor.
3270 */
3271 while (depth1 > depth2) {
3272 depth1--;
3273 node1 = node1->parent;
3274 }
3275 while (depth2 > depth1) {
3276 depth2--;
3277 node2 = node2->parent;
3278 }
3279 while (node1->parent != node2->parent) {
3280 node1 = node1->parent;
3281 node2 = node2->parent;
3282 /* should not happen but just in case ... */
3283 if ((node1 == NULL) || (node2 == NULL))
3284 return(-2);
3285 }
3286 /*
3287 * Find who's first.
3288 */
3289 if (node1 == node2->prev)
3290 return(1);
3291 if (node1 == node2->next)
3292 return(-1);
3293 /*
3294 * Speedup using document order if availble.
3295 */
3296 if ((node1->type == XML_ELEMENT_NODE) &&
3297 (node2->type == XML_ELEMENT_NODE) &&
3298 (0 > (long) node1->content) &&
3299 (0 > (long) node2->content) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +00003300 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003301
3302 l1 = -((long) node1->content);
3303 l2 = -((long) node2->content);
3304 if (l1 < l2)
3305 return(1);
3306 if (l1 > l2)
3307 return(-1);
3308 }
3309
3310 for (cur = node1->next;cur != NULL;cur = cur->next)
3311 if (cur == node2)
3312 return(1);
3313 return(-1); /* assume there is no sibling list corruption */
3314}
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003315#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003316
Owen Taylor3473f882001-02-23 17:55:21 +00003317/**
3318 * xmlXPathNodeSetSort:
3319 * @set: the node set
3320 *
3321 * Sort the node set in document order
3322 */
3323void
3324xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003325 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003326 xmlNodePtr tmp;
3327
3328 if (set == NULL)
3329 return;
3330
3331 /* Use Shell's sort to sort the node-set */
3332 len = set->nodeNr;
3333 for (incr = len / 2; incr > 0; incr /= 2) {
3334 for (i = incr; i < len; i++) {
3335 j = i - incr;
3336 while (j >= 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003337#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003338 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3339 set->nodeTab[j + incr]) == -1)
3340#else
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003341 if (xmlXPathCmpNodes(set->nodeTab[j],
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003342 set->nodeTab[j + incr]) == -1)
3343#endif
3344 {
Owen Taylor3473f882001-02-23 17:55:21 +00003345 tmp = set->nodeTab[j];
3346 set->nodeTab[j] = set->nodeTab[j + incr];
3347 set->nodeTab[j + incr] = tmp;
3348 j -= incr;
3349 } else
3350 break;
3351 }
3352 }
3353 }
3354}
3355
3356#define XML_NODESET_DEFAULT 10
3357/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003358 * xmlXPathNodeSetDupNs:
3359 * @node: the parent node of the namespace XPath node
3360 * @ns: the libxml namespace declaration node.
3361 *
3362 * Namespace node in libxml don't match the XPath semantic. In a node set
3363 * the namespace nodes are duplicated and the next pointer is set to the
3364 * parent node in the XPath semantic.
3365 *
3366 * Returns the newly created object.
3367 */
3368static xmlNodePtr
3369xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3370 xmlNsPtr cur;
3371
3372 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3373 return(NULL);
3374 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3375 return((xmlNodePtr) ns);
3376
3377 /*
3378 * Allocate a new Namespace and fill the fields.
3379 */
3380 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3381 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003382 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003383 return(NULL);
3384 }
3385 memset(cur, 0, sizeof(xmlNs));
3386 cur->type = XML_NAMESPACE_DECL;
3387 if (ns->href != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003388 cur->href = xmlStrdup(ns->href);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003389 if (ns->prefix != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003390 cur->prefix = xmlStrdup(ns->prefix);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003391 cur->next = (xmlNsPtr) node;
3392 return((xmlNodePtr) cur);
3393}
3394
3395/**
3396 * xmlXPathNodeSetFreeNs:
3397 * @ns: the XPath namespace node found in a nodeset.
3398 *
William M. Brack08171912003-12-29 02:52:11 +00003399 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003400 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00003401 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003402 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00003403void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003404xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3405 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3406 return;
3407
3408 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3409 if (ns->href != NULL)
3410 xmlFree((xmlChar *)ns->href);
3411 if (ns->prefix != NULL)
3412 xmlFree((xmlChar *)ns->prefix);
3413 xmlFree(ns);
3414 }
3415}
3416
3417/**
Owen Taylor3473f882001-02-23 17:55:21 +00003418 * xmlXPathNodeSetCreate:
3419 * @val: an initial xmlNodePtr, or NULL
3420 *
3421 * Create a new xmlNodeSetPtr of type double and of value @val
3422 *
3423 * Returns the newly created object.
3424 */
3425xmlNodeSetPtr
3426xmlXPathNodeSetCreate(xmlNodePtr val) {
3427 xmlNodeSetPtr ret;
3428
3429 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3430 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003431 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003432 return(NULL);
3433 }
3434 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3435 if (val != NULL) {
3436 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3437 sizeof(xmlNodePtr));
3438 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003439 xmlXPathErrMemory(NULL, "creating nodeset\n");
3440 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003441 return(NULL);
3442 }
3443 memset(ret->nodeTab, 0 ,
3444 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3445 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003446 if (val->type == XML_NAMESPACE_DECL) {
3447 xmlNsPtr ns = (xmlNsPtr) val;
3448
3449 ret->nodeTab[ret->nodeNr++] =
3450 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3451 } else
3452 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003453 }
3454 return(ret);
3455}
3456
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003457/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003458 * xmlXPathNodeSetCreateSize:
3459 * @size: the initial size of the set
3460 *
3461 * Create a new xmlNodeSetPtr of type double and of value @val
3462 *
3463 * Returns the newly created object.
3464 */
3465static xmlNodeSetPtr
3466xmlXPathNodeSetCreateSize(int size) {
3467 xmlNodeSetPtr ret;
3468
3469 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3470 if (ret == NULL) {
3471 xmlXPathErrMemory(NULL, "creating nodeset\n");
3472 return(NULL);
3473 }
3474 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3475 if (size < XML_NODESET_DEFAULT)
3476 size = XML_NODESET_DEFAULT;
3477 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3478 if (ret->nodeTab == NULL) {
3479 xmlXPathErrMemory(NULL, "creating nodeset\n");
3480 xmlFree(ret);
3481 return(NULL);
3482 }
3483 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
Daniel Veillard45490ae2008-07-29 09:13:19 +00003484 ret->nodeMax = size;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003485 return(ret);
3486}
3487
3488/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003489 * xmlXPathNodeSetContains:
3490 * @cur: the node-set
3491 * @val: the node
3492 *
3493 * checks whether @cur contains @val
3494 *
3495 * Returns true (1) if @cur contains @val, false (0) otherwise
3496 */
3497int
3498xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3499 int i;
3500
Daniel Veillarda82b1822004-11-08 16:24:57 +00003501 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003502 if (val->type == XML_NAMESPACE_DECL) {
3503 for (i = 0; i < cur->nodeNr; i++) {
3504 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3505 xmlNsPtr ns1, ns2;
3506
3507 ns1 = (xmlNsPtr) val;
3508 ns2 = (xmlNsPtr) cur->nodeTab[i];
3509 if (ns1 == ns2)
3510 return(1);
3511 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3512 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3513 return(1);
3514 }
3515 }
3516 } else {
3517 for (i = 0; i < cur->nodeNr; i++) {
3518 if (cur->nodeTab[i] == val)
3519 return(1);
3520 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003521 }
3522 return(0);
3523}
3524
3525/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003526 * xmlXPathNodeSetAddNs:
3527 * @cur: the initial node set
3528 * @node: the hosting node
3529 * @ns: a the namespace node
3530 *
3531 * add a new namespace node to an existing NodeSet
3532 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00003533void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003534xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3535 int i;
3536
Daniel Veillard45490ae2008-07-29 09:13:19 +00003537
Daniel Veillarda82b1822004-11-08 16:24:57 +00003538 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3539 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003540 (node->type != XML_ELEMENT_NODE))
3541 return;
3542
William M. Brack08171912003-12-29 02:52:11 +00003543 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003544 /*
William M. Brack08171912003-12-29 02:52:11 +00003545 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003546 */
3547 for (i = 0;i < cur->nodeNr;i++) {
3548 if ((cur->nodeTab[i] != NULL) &&
3549 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00003550 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003551 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3552 return;
3553 }
3554
3555 /*
3556 * grow the nodeTab if needed
3557 */
3558 if (cur->nodeMax == 0) {
3559 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3560 sizeof(xmlNodePtr));
3561 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003562 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003563 return;
3564 }
3565 memset(cur->nodeTab, 0 ,
3566 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3567 cur->nodeMax = XML_NODESET_DEFAULT;
3568 } else if (cur->nodeNr == cur->nodeMax) {
3569 xmlNodePtr *temp;
3570
Chris Evansd7958b22011-03-23 08:13:06 +08003571 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003572 sizeof(xmlNodePtr));
3573 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003574 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003575 return;
3576 }
Chris Evansd7958b22011-03-23 08:13:06 +08003577 cur->nodeMax *= 2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003578 cur->nodeTab = temp;
3579 }
3580 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3581}
3582
3583/**
Owen Taylor3473f882001-02-23 17:55:21 +00003584 * xmlXPathNodeSetAdd:
3585 * @cur: the initial node set
3586 * @val: a new xmlNodePtr
3587 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003588 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00003589 */
3590void
3591xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3592 int i;
3593
Daniel Veillarda82b1822004-11-08 16:24:57 +00003594 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003595
Daniel Veillardef0b4502003-03-24 13:57:34 +00003596#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00003597 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3598 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00003599#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00003600
William M. Brack08171912003-12-29 02:52:11 +00003601 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003602 /*
William M. Brack08171912003-12-29 02:52:11 +00003603 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00003604 */
3605 for (i = 0;i < cur->nodeNr;i++)
3606 if (cur->nodeTab[i] == val) return;
3607
3608 /*
3609 * grow the nodeTab if needed
3610 */
3611 if (cur->nodeMax == 0) {
3612 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3613 sizeof(xmlNodePtr));
3614 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003615 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003616 return;
3617 }
3618 memset(cur->nodeTab, 0 ,
3619 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3620 cur->nodeMax = XML_NODESET_DEFAULT;
3621 } else if (cur->nodeNr == cur->nodeMax) {
3622 xmlNodePtr *temp;
3623
Daniel Veillard0cbeb502010-11-15 12:06:29 +01003624 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003625 sizeof(xmlNodePtr));
3626 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003627 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003628 return;
3629 }
Daniel Veillard0cbeb502010-11-15 12:06:29 +01003630 cur->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003631 cur->nodeTab = temp;
3632 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003633 if (val->type == XML_NAMESPACE_DECL) {
3634 xmlNsPtr ns = (xmlNsPtr) val;
3635
Daniel Veillard45490ae2008-07-29 09:13:19 +00003636 cur->nodeTab[cur->nodeNr++] =
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003637 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3638 } else
3639 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003640}
3641
3642/**
3643 * xmlXPathNodeSetAddUnique:
3644 * @cur: the initial node set
3645 * @val: a new xmlNodePtr
3646 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003647 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00003648 * when we are sure the node is not already in the set.
3649 */
3650void
3651xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00003652 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003653
Daniel Veillardef0b4502003-03-24 13:57:34 +00003654#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00003655 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3656 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00003657#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00003658
William M. Brack08171912003-12-29 02:52:11 +00003659 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003660 /*
3661 * grow the nodeTab if needed
3662 */
3663 if (cur->nodeMax == 0) {
3664 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3665 sizeof(xmlNodePtr));
3666 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003667 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003668 return;
3669 }
3670 memset(cur->nodeTab, 0 ,
3671 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3672 cur->nodeMax = XML_NODESET_DEFAULT;
3673 } else if (cur->nodeNr == cur->nodeMax) {
3674 xmlNodePtr *temp;
3675
Chris Evansd7958b22011-03-23 08:13:06 +08003676 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003677 sizeof(xmlNodePtr));
3678 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003679 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003680 return;
3681 }
3682 cur->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08003683 cur->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003684 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003685 if (val->type == XML_NAMESPACE_DECL) {
3686 xmlNsPtr ns = (xmlNsPtr) val;
3687
Daniel Veillard45490ae2008-07-29 09:13:19 +00003688 cur->nodeTab[cur->nodeNr++] =
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003689 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3690 } else
3691 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003692}
3693
3694/**
3695 * xmlXPathNodeSetMerge:
3696 * @val1: the first NodeSet or NULL
3697 * @val2: the second NodeSet
3698 *
3699 * Merges two nodesets, all nodes from @val2 are added to @val1
3700 * if @val1 is NULL, a new set is created and copied from @val2
3701 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003702 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003703 */
3704xmlNodeSetPtr
3705xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003706 int i, j, initNr, skip;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003707 xmlNodePtr n1, n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003708
3709 if (val2 == NULL) return(val1);
3710 if (val1 == NULL) {
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003711 val1 = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00003712 if (val1 == NULL)
3713 return (NULL);
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003714#if 0
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003715 /*
3716 * TODO: The optimization won't work in every case, since
3717 * those nasty namespace nodes need to be added with
3718 * xmlXPathNodeSetDupNs() to the set; thus a pure
3719 * memcpy is not possible.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00003720 * If there was a flag on the nodesetval, indicating that
3721 * some temporary nodes are in, that would be helpfull.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003722 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00003723 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003724 * Optimization: Create an equally sized node-set
3725 * and memcpy the content.
3726 */
3727 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3728 if (val1 == NULL)
3729 return(NULL);
3730 if (val2->nodeNr != 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003731 if (val2->nodeNr == 1)
3732 *(val1->nodeTab) = *(val2->nodeTab);
3733 else {
3734 memcpy(val1->nodeTab, val2->nodeTab,
3735 val2->nodeNr * sizeof(xmlNodePtr));
3736 }
3737 val1->nodeNr = val2->nodeNr;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003738 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003739 return(val1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003740#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003741 }
3742
William M. Brack08171912003-12-29 02:52:11 +00003743 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003744 initNr = val1->nodeNr;
3745
3746 for (i = 0;i < val2->nodeNr;i++) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00003747 n2 = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00003748 /*
William M. Brack08171912003-12-29 02:52:11 +00003749 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003750 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003751 skip = 0;
3752 for (j = 0; j < initNr; j++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003753 n1 = val1->nodeTab[j];
3754 if (n1 == n2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003755 skip = 1;
3756 break;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003757 } else if ((n1->type == XML_NAMESPACE_DECL) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +00003758 (n2->type == XML_NAMESPACE_DECL)) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003759 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3760 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3761 ((xmlNsPtr) n2)->prefix)))
3762 {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003763 skip = 1;
3764 break;
3765 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003766 }
3767 }
3768 if (skip)
3769 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00003770
3771 /*
3772 * grow the nodeTab if needed
3773 */
3774 if (val1->nodeMax == 0) {
3775 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3776 sizeof(xmlNodePtr));
3777 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003778 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003779 return(NULL);
3780 }
3781 memset(val1->nodeTab, 0 ,
3782 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3783 val1->nodeMax = XML_NODESET_DEFAULT;
3784 } else if (val1->nodeNr == val1->nodeMax) {
3785 xmlNodePtr *temp;
3786
Chris Evansd7958b22011-03-23 08:13:06 +08003787 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
Owen Taylor3473f882001-02-23 17:55:21 +00003788 sizeof(xmlNodePtr));
3789 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003790 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003791 return(NULL);
3792 }
3793 val1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08003794 val1->nodeMax *= 2;
Owen Taylor3473f882001-02-23 17:55:21 +00003795 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003796 if (n2->type == XML_NAMESPACE_DECL) {
3797 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003798
3799 val1->nodeTab[val1->nodeNr++] =
3800 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3801 } else
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003802 val1->nodeTab[val1->nodeNr++] = n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003803 }
3804
3805 return(val1);
3806}
3807
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003808#if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
Owen Taylor3473f882001-02-23 17:55:21 +00003809/**
Daniel Veillard75be0132002-03-13 10:03:35 +00003810 * xmlXPathNodeSetMergeUnique:
3811 * @val1: the first NodeSet or NULL
3812 * @val2: the second NodeSet
3813 *
3814 * Merges two nodesets, all nodes from @val2 are added to @val1
3815 * if @val1 is NULL, a new set is created and copied from @val2
3816 *
3817 * Returns @val1 once extended or NULL in case of error.
3818 */
3819static xmlNodeSetPtr
3820xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00003821 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00003822
3823 if (val2 == NULL) return(val1);
3824 if (val1 == NULL) {
3825 val1 = xmlXPathNodeSetCreate(NULL);
3826 }
Daniel Veillardf88d8492008-04-01 08:00:31 +00003827 if (val1 == NULL)
3828 return (NULL);
Daniel Veillard75be0132002-03-13 10:03:35 +00003829
William M. Brack08171912003-12-29 02:52:11 +00003830 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00003831
3832 for (i = 0;i < val2->nodeNr;i++) {
3833 /*
3834 * grow the nodeTab if needed
3835 */
3836 if (val1->nodeMax == 0) {
3837 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3838 sizeof(xmlNodePtr));
3839 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003840 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00003841 return(NULL);
3842 }
3843 memset(val1->nodeTab, 0 ,
3844 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3845 val1->nodeMax = XML_NODESET_DEFAULT;
3846 } else if (val1->nodeNr == val1->nodeMax) {
3847 xmlNodePtr *temp;
3848
3849 val1->nodeMax *= 2;
3850 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3851 sizeof(xmlNodePtr));
3852 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003853 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00003854 return(NULL);
3855 }
3856 val1->nodeTab = temp;
3857 }
3858 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3859 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
3860
3861 val1->nodeTab[val1->nodeNr++] =
3862 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3863 } else
3864 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
3865 }
3866
3867 return(val1);
3868}
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003869#endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3870
3871/**
3872 * xmlXPathNodeSetMergeAndClear:
3873 * @set1: the first NodeSet or NULL
3874 * @set2: the second NodeSet
3875 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3876 *
3877 * Merges two nodesets, all nodes from @set2 are added to @set1
3878 * if @set1 is NULL, a new set is created and copied from @set2.
3879 * Checks for duplicate nodes. Clears set2.
3880 *
3881 * Returns @set1 once extended or NULL in case of error.
3882 */
3883static xmlNodeSetPtr
3884xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3885 int hasNullEntries)
3886{
3887 if ((set1 == NULL) && (hasNullEntries == 0)) {
3888 /*
3889 * Note that doing a memcpy of the list, namespace nodes are
3890 * just assigned to set1, since set2 is cleared anyway.
3891 */
3892 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3893 if (set1 == NULL)
3894 return(NULL);
3895 if (set2->nodeNr != 0) {
3896 memcpy(set1->nodeTab, set2->nodeTab,
3897 set2->nodeNr * sizeof(xmlNodePtr));
3898 set1->nodeNr = set2->nodeNr;
3899 }
3900 } else {
3901 int i, j, initNbSet1;
3902 xmlNodePtr n1, n2;
3903
3904 if (set1 == NULL)
Daniel Veillardf88d8492008-04-01 08:00:31 +00003905 set1 = xmlXPathNodeSetCreate(NULL);
3906 if (set1 == NULL)
3907 return (NULL);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003908
Daniel Veillard45490ae2008-07-29 09:13:19 +00003909 initNbSet1 = set1->nodeNr;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003910 for (i = 0;i < set2->nodeNr;i++) {
3911 n2 = set2->nodeTab[i];
3912 /*
3913 * Skip NULLed entries.
3914 */
3915 if (n2 == NULL)
3916 continue;
3917 /*
3918 * Skip duplicates.
3919 */
3920 for (j = 0; j < initNbSet1; j++) {
3921 n1 = set1->nodeTab[j];
Daniel Veillard45490ae2008-07-29 09:13:19 +00003922 if (n1 == n2) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003923 goto skip_node;
3924 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3925 (n2->type == XML_NAMESPACE_DECL))
Daniel Veillard45490ae2008-07-29 09:13:19 +00003926 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003927 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3928 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3929 ((xmlNsPtr) n2)->prefix)))
3930 {
3931 /*
3932 * Free the namespace node.
3933 */
3934 set2->nodeTab[i] = NULL;
3935 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3936 goto skip_node;
3937 }
3938 }
3939 }
3940 /*
3941 * grow the nodeTab if needed
3942 */
3943 if (set1->nodeMax == 0) {
3944 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3945 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3946 if (set1->nodeTab == NULL) {
3947 xmlXPathErrMemory(NULL, "merging nodeset\n");
3948 return(NULL);
3949 }
3950 memset(set1->nodeTab, 0,
3951 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3952 set1->nodeMax = XML_NODESET_DEFAULT;
3953 } else if (set1->nodeNr >= set1->nodeMax) {
3954 xmlNodePtr *temp;
Daniel Veillard45490ae2008-07-29 09:13:19 +00003955
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003956 temp = (xmlNodePtr *) xmlRealloc(
Chris Evansd7958b22011-03-23 08:13:06 +08003957 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003958 if (temp == NULL) {
3959 xmlXPathErrMemory(NULL, "merging nodeset\n");
3960 return(NULL);
3961 }
3962 set1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08003963 set1->nodeMax *= 2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003964 }
3965 if (n2->type == XML_NAMESPACE_DECL) {
3966 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard45490ae2008-07-29 09:13:19 +00003967
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003968 set1->nodeTab[set1->nodeNr++] =
3969 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3970 } else
3971 set1->nodeTab[set1->nodeNr++] = n2;
3972skip_node:
3973 {}
3974 }
3975 }
3976 set2->nodeNr = 0;
3977 return(set1);
3978}
3979
3980/**
3981 * xmlXPathNodeSetMergeAndClearNoDupls:
3982 * @set1: the first NodeSet or NULL
3983 * @set2: the second NodeSet
3984 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3985 *
3986 * Merges two nodesets, all nodes from @set2 are added to @set1
3987 * if @set1 is NULL, a new set is created and copied from @set2.
3988 * Doesn't chack for duplicate nodes. Clears set2.
3989 *
3990 * Returns @set1 once extended or NULL in case of error.
3991 */
3992static xmlNodeSetPtr
3993xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3994 int hasNullEntries)
Daniel Veillard45490ae2008-07-29 09:13:19 +00003995{
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003996 if (set2 == NULL)
3997 return(set1);
3998 if ((set1 == NULL) && (hasNullEntries == 0)) {
3999 /*
4000 * Note that doing a memcpy of the list, namespace nodes are
4001 * just assigned to set1, since set2 is cleared anyway.
4002 */
4003 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
4004 if (set1 == NULL)
4005 return(NULL);
4006 if (set2->nodeNr != 0) {
4007 memcpy(set1->nodeTab, set2->nodeTab,
4008 set2->nodeNr * sizeof(xmlNodePtr));
4009 set1->nodeNr = set2->nodeNr;
4010 }
4011 } else {
4012 int i;
4013 xmlNodePtr n2;
4014
4015 if (set1 == NULL)
4016 set1 = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004017 if (set1 == NULL)
4018 return (NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004019
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004020 for (i = 0;i < set2->nodeNr;i++) {
4021 n2 = set2->nodeTab[i];
4022 /*
4023 * Skip NULLed entries.
4024 */
4025 if (n2 == NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004026 continue;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004027 if (set1->nodeMax == 0) {
4028 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4029 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4030 if (set1->nodeTab == NULL) {
4031 xmlXPathErrMemory(NULL, "merging nodeset\n");
4032 return(NULL);
4033 }
4034 memset(set1->nodeTab, 0,
4035 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4036 set1->nodeMax = XML_NODESET_DEFAULT;
4037 } else if (set1->nodeNr >= set1->nodeMax) {
4038 xmlNodePtr *temp;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004039
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004040 temp = (xmlNodePtr *) xmlRealloc(
Chris Evansd7958b22011-03-23 08:13:06 +08004041 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004042 if (temp == NULL) {
4043 xmlXPathErrMemory(NULL, "merging nodeset\n");
4044 return(NULL);
4045 }
4046 set1->nodeTab = temp;
Chris Evansd7958b22011-03-23 08:13:06 +08004047 set1->nodeMax *= 2;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004048 }
4049 set1->nodeTab[set1->nodeNr++] = n2;
4050 }
4051 }
4052 set2->nodeNr = 0;
4053 return(set1);
4054}
Daniel Veillard75be0132002-03-13 10:03:35 +00004055
4056/**
Owen Taylor3473f882001-02-23 17:55:21 +00004057 * xmlXPathNodeSetDel:
4058 * @cur: the initial node set
4059 * @val: an xmlNodePtr
4060 *
4061 * Removes an xmlNodePtr from an existing NodeSet
4062 */
4063void
4064xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4065 int i;
4066
4067 if (cur == NULL) return;
4068 if (val == NULL) return;
4069
4070 /*
William M. Brack08171912003-12-29 02:52:11 +00004071 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00004072 */
4073 for (i = 0;i < cur->nodeNr;i++)
4074 if (cur->nodeTab[i] == val) break;
4075
William M. Brack08171912003-12-29 02:52:11 +00004076 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00004077#ifdef DEBUG
Daniel Veillard45490ae2008-07-29 09:13:19 +00004078 xmlGenericError(xmlGenericErrorContext,
Owen Taylor3473f882001-02-23 17:55:21 +00004079 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4080 val->name);
4081#endif
4082 return;
4083 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004084 if ((cur->nodeTab[i] != NULL) &&
4085 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4086 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004087 cur->nodeNr--;
4088 for (;i < cur->nodeNr;i++)
4089 cur->nodeTab[i] = cur->nodeTab[i + 1];
4090 cur->nodeTab[cur->nodeNr] = NULL;
4091}
4092
4093/**
4094 * xmlXPathNodeSetRemove:
4095 * @cur: the initial node set
4096 * @val: the index to remove
4097 *
4098 * Removes an entry from an existing NodeSet list.
4099 */
4100void
4101xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4102 if (cur == NULL) return;
4103 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004104 if ((cur->nodeTab[val] != NULL) &&
4105 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4106 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00004107 cur->nodeNr--;
4108 for (;val < cur->nodeNr;val++)
4109 cur->nodeTab[val] = cur->nodeTab[val + 1];
4110 cur->nodeTab[cur->nodeNr] = NULL;
4111}
4112
4113/**
4114 * xmlXPathFreeNodeSet:
4115 * @obj: the xmlNodeSetPtr to free
4116 *
4117 * Free the NodeSet compound (not the actual nodes !).
4118 */
4119void
4120xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4121 if (obj == NULL) return;
4122 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004123 int i;
4124
William M. Brack08171912003-12-29 02:52:11 +00004125 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004126 for (i = 0;i < obj->nodeNr;i++)
4127 if ((obj->nodeTab[i] != NULL) &&
4128 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4129 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004130 xmlFree(obj->nodeTab);
4131 }
Owen Taylor3473f882001-02-23 17:55:21 +00004132 xmlFree(obj);
4133}
4134
4135/**
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004136 * xmlXPathNodeSetClear:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004137 * @set: the node set to clear
Daniel Veillard45490ae2008-07-29 09:13:19 +00004138 *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004139 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4140 * are feed), but does *not* free the list itself. Sets the length of the
4141 * list to 0.
4142 */
4143static void
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004144xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4145{
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004146 if ((set == NULL) || (set->nodeNr <= 0))
4147 return;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004148 else if (hasNsNodes) {
4149 int i;
4150 xmlNodePtr node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004151
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004152 for (i = 0; i < set->nodeNr; i++) {
4153 node = set->nodeTab[i];
4154 if ((node != NULL) &&
4155 (node->type == XML_NAMESPACE_DECL))
4156 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004157 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004158 }
4159 set->nodeNr = 0;
4160}
4161
4162/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004163 * xmlXPathNodeSetClearFromPos:
4164 * @set: the node set to be cleared
4165 * @pos: the start position to clear from
Daniel Veillard45490ae2008-07-29 09:13:19 +00004166 *
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004167 * Clears the list from temporary XPath objects (e.g. namespace nodes
4168 * are feed) starting with the entry at @pos, but does *not* free the list
4169 * itself. Sets the length of the list to @pos.
4170 */
4171static void
4172xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4173{
4174 if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4175 return;
4176 else if ((hasNsNodes)) {
4177 int i;
4178 xmlNodePtr node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004179
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004180 for (i = pos; i < set->nodeNr; i++) {
4181 node = set->nodeTab[i];
4182 if ((node != NULL) &&
4183 (node->type == XML_NAMESPACE_DECL))
4184 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
Daniel Veillard45490ae2008-07-29 09:13:19 +00004185 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004186 }
4187 set->nodeNr = pos;
4188}
4189
4190/**
Owen Taylor3473f882001-02-23 17:55:21 +00004191 * xmlXPathFreeValueTree:
4192 * @obj: the xmlNodeSetPtr to free
4193 *
4194 * Free the NodeSet compound and the actual tree, this is different
4195 * from xmlXPathFreeNodeSet()
4196 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004197static void
Owen Taylor3473f882001-02-23 17:55:21 +00004198xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4199 int i;
4200
4201 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00004202
4203 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004204 for (i = 0;i < obj->nodeNr;i++) {
4205 if (obj->nodeTab[i] != NULL) {
4206 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4207 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4208 } else {
4209 xmlFreeNodeList(obj->nodeTab[i]);
4210 }
4211 }
4212 }
Owen Taylor3473f882001-02-23 17:55:21 +00004213 xmlFree(obj->nodeTab);
4214 }
Owen Taylor3473f882001-02-23 17:55:21 +00004215 xmlFree(obj);
4216}
4217
4218#if defined(DEBUG) || defined(DEBUG_STEP)
4219/**
4220 * xmlGenericErrorContextNodeSet:
4221 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00004222 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00004223 *
4224 * Quick display of a NodeSet
4225 */
4226void
4227xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4228 int i;
4229
4230 if (output == NULL) output = xmlGenericErrorContext;
4231 if (obj == NULL) {
4232 fprintf(output, "NodeSet == NULL !\n");
4233 return;
4234 }
4235 if (obj->nodeNr == 0) {
4236 fprintf(output, "NodeSet is empty\n");
4237 return;
4238 }
4239 if (obj->nodeTab == NULL) {
4240 fprintf(output, " nodeTab == NULL !\n");
4241 return;
4242 }
4243 for (i = 0; i < obj->nodeNr; i++) {
4244 if (obj->nodeTab[i] == NULL) {
4245 fprintf(output, " NULL !\n");
4246 return;
4247 }
4248 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4249 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4250 fprintf(output, " /");
4251 else if (obj->nodeTab[i]->name == NULL)
4252 fprintf(output, " noname!");
4253 else fprintf(output, " %s", obj->nodeTab[i]->name);
4254 }
4255 fprintf(output, "\n");
4256}
4257#endif
4258
4259/**
4260 * xmlXPathNewNodeSet:
4261 * @val: the NodePtr value
4262 *
4263 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4264 * it with the single Node @val
4265 *
4266 * Returns the newly created object.
4267 */
4268xmlXPathObjectPtr
4269xmlXPathNewNodeSet(xmlNodePtr val) {
4270 xmlXPathObjectPtr ret;
4271
4272 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4273 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004274 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004275 return(NULL);
4276 }
4277 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4278 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00004279 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004280 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00004281 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004282#ifdef XP_DEBUG_OBJ_USAGE
4283 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4284#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004285 return(ret);
4286}
4287
4288/**
4289 * xmlXPathNewValueTree:
4290 * @val: the NodePtr value
4291 *
4292 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4293 * it with the tree root @val
4294 *
4295 * Returns the newly created object.
4296 */
4297xmlXPathObjectPtr
4298xmlXPathNewValueTree(xmlNodePtr val) {
4299 xmlXPathObjectPtr ret;
4300
4301 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4302 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004303 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004304 return(NULL);
4305 }
4306 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4307 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00004308 ret->boolval = 1;
4309 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00004310 ret->nodesetval = xmlXPathNodeSetCreate(val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004311#ifdef XP_DEBUG_OBJ_USAGE
4312 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4313#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004314 return(ret);
4315}
4316
4317/**
4318 * xmlXPathNewNodeSetList:
4319 * @val: an existing NodeSet
4320 *
4321 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4322 * it with the Nodeset @val
4323 *
4324 * Returns the newly created object.
4325 */
4326xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004327xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4328{
Owen Taylor3473f882001-02-23 17:55:21 +00004329 xmlXPathObjectPtr ret;
4330 int i;
4331
4332 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004333 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00004334 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004335 ret = xmlXPathNewNodeSet(NULL);
4336 else {
4337 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004338 if (ret)
4339 for (i = 1; i < val->nodeNr; ++i)
4340 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004341 }
Owen Taylor3473f882001-02-23 17:55:21 +00004342
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004343 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004344}
4345
4346/**
4347 * xmlXPathWrapNodeSet:
4348 * @val: the NodePtr value
4349 *
4350 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4351 *
4352 * Returns the newly created object.
4353 */
4354xmlXPathObjectPtr
4355xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4356 xmlXPathObjectPtr ret;
4357
4358 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4359 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004360 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004361 return(NULL);
4362 }
4363 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4364 ret->type = XPATH_NODESET;
4365 ret->nodesetval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004366#ifdef XP_DEBUG_OBJ_USAGE
4367 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4368#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004369 return(ret);
4370}
4371
4372/**
4373 * xmlXPathFreeNodeSetList:
4374 * @obj: an existing NodeSetList object
4375 *
4376 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4377 * the list contrary to xmlXPathFreeObject().
4378 */
4379void
4380xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4381 if (obj == NULL) return;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004382#ifdef XP_DEBUG_OBJ_USAGE
4383 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4384#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004385 xmlFree(obj);
4386}
4387
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004388/**
4389 * xmlXPathDifference:
4390 * @nodes1: a node-set
4391 * @nodes2: a node-set
4392 *
4393 * Implements the EXSLT - Sets difference() function:
4394 * node-set set:difference (node-set, node-set)
4395 *
4396 * Returns the difference between the two node sets, or nodes1 if
4397 * nodes2 is empty
4398 */
4399xmlNodeSetPtr
4400xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4401 xmlNodeSetPtr ret;
4402 int i, l1;
4403 xmlNodePtr cur;
4404
4405 if (xmlXPathNodeSetIsEmpty(nodes2))
4406 return(nodes1);
4407
4408 ret = xmlXPathNodeSetCreate(NULL);
4409 if (xmlXPathNodeSetIsEmpty(nodes1))
4410 return(ret);
4411
4412 l1 = xmlXPathNodeSetGetLength(nodes1);
4413
4414 for (i = 0; i < l1; i++) {
4415 cur = xmlXPathNodeSetItem(nodes1, i);
4416 if (!xmlXPathNodeSetContains(nodes2, cur))
4417 xmlXPathNodeSetAddUnique(ret, cur);
4418 }
4419 return(ret);
4420}
4421
4422/**
4423 * xmlXPathIntersection:
4424 * @nodes1: a node-set
4425 * @nodes2: a node-set
4426 *
4427 * Implements the EXSLT - Sets intersection() function:
4428 * node-set set:intersection (node-set, node-set)
4429 *
4430 * Returns a node set comprising the nodes that are within both the
4431 * node sets passed as arguments
4432 */
4433xmlNodeSetPtr
4434xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4435 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4436 int i, l1;
4437 xmlNodePtr cur;
4438
Daniel Veillardf88d8492008-04-01 08:00:31 +00004439 if (ret == NULL)
4440 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004441 if (xmlXPathNodeSetIsEmpty(nodes1))
4442 return(ret);
4443 if (xmlXPathNodeSetIsEmpty(nodes2))
4444 return(ret);
4445
4446 l1 = xmlXPathNodeSetGetLength(nodes1);
4447
4448 for (i = 0; i < l1; i++) {
4449 cur = xmlXPathNodeSetItem(nodes1, i);
4450 if (xmlXPathNodeSetContains(nodes2, cur))
4451 xmlXPathNodeSetAddUnique(ret, cur);
4452 }
4453 return(ret);
4454}
4455
4456/**
4457 * xmlXPathDistinctSorted:
4458 * @nodes: a node-set, sorted by document order
4459 *
4460 * Implements the EXSLT - Sets distinct() function:
4461 * node-set set:distinct (node-set)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004462 *
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004463 * Returns a subset of the nodes contained in @nodes, or @nodes if
4464 * it is empty
4465 */
4466xmlNodeSetPtr
4467xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4468 xmlNodeSetPtr ret;
4469 xmlHashTablePtr hash;
4470 int i, l;
4471 xmlChar * strval;
4472 xmlNodePtr cur;
4473
4474 if (xmlXPathNodeSetIsEmpty(nodes))
4475 return(nodes);
4476
4477 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004478 if (ret == NULL)
4479 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004480 l = xmlXPathNodeSetGetLength(nodes);
4481 hash = xmlHashCreate (l);
4482 for (i = 0; i < l; i++) {
4483 cur = xmlXPathNodeSetItem(nodes, i);
4484 strval = xmlXPathCastNodeToString(cur);
4485 if (xmlHashLookup(hash, strval) == NULL) {
4486 xmlHashAddEntry(hash, strval, strval);
4487 xmlXPathNodeSetAddUnique(ret, cur);
4488 } else {
4489 xmlFree(strval);
4490 }
4491 }
4492 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4493 return(ret);
4494}
4495
4496/**
4497 * xmlXPathDistinct:
4498 * @nodes: a node-set
4499 *
4500 * Implements the EXSLT - Sets distinct() function:
4501 * node-set set:distinct (node-set)
4502 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4503 * is called with the sorted node-set
4504 *
4505 * Returns a subset of the nodes contained in @nodes, or @nodes if
4506 * it is empty
4507 */
4508xmlNodeSetPtr
4509xmlXPathDistinct (xmlNodeSetPtr nodes) {
4510 if (xmlXPathNodeSetIsEmpty(nodes))
4511 return(nodes);
4512
4513 xmlXPathNodeSetSort(nodes);
4514 return(xmlXPathDistinctSorted(nodes));
4515}
4516
4517/**
4518 * xmlXPathHasSameNodes:
4519 * @nodes1: a node-set
4520 * @nodes2: a node-set
4521 *
4522 * Implements the EXSLT - Sets has-same-nodes function:
4523 * boolean set:has-same-node(node-set, node-set)
4524 *
4525 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4526 * otherwise
4527 */
4528int
4529xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4530 int i, l;
4531 xmlNodePtr cur;
4532
4533 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4534 xmlXPathNodeSetIsEmpty(nodes2))
4535 return(0);
4536
4537 l = xmlXPathNodeSetGetLength(nodes1);
4538 for (i = 0; i < l; i++) {
4539 cur = xmlXPathNodeSetItem(nodes1, i);
4540 if (xmlXPathNodeSetContains(nodes2, cur))
4541 return(1);
4542 }
4543 return(0);
4544}
4545
4546/**
4547 * xmlXPathNodeLeadingSorted:
4548 * @nodes: a node-set, sorted by document order
4549 * @node: a node
4550 *
4551 * Implements the EXSLT - Sets leading() function:
4552 * node-set set:leading (node-set, node-set)
4553 *
4554 * Returns the nodes in @nodes that precede @node in document order,
4555 * @nodes if @node is NULL or an empty node-set if @nodes
4556 * doesn't contain @node
4557 */
4558xmlNodeSetPtr
4559xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4560 int i, l;
4561 xmlNodePtr cur;
4562 xmlNodeSetPtr ret;
4563
4564 if (node == NULL)
4565 return(nodes);
4566
4567 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004568 if (ret == NULL)
4569 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004570 if (xmlXPathNodeSetIsEmpty(nodes) ||
4571 (!xmlXPathNodeSetContains(nodes, node)))
4572 return(ret);
4573
4574 l = xmlXPathNodeSetGetLength(nodes);
4575 for (i = 0; i < l; i++) {
4576 cur = xmlXPathNodeSetItem(nodes, i);
4577 if (cur == node)
4578 break;
4579 xmlXPathNodeSetAddUnique(ret, cur);
4580 }
4581 return(ret);
4582}
4583
4584/**
4585 * xmlXPathNodeLeading:
4586 * @nodes: a node-set
4587 * @node: a node
4588 *
4589 * Implements the EXSLT - Sets leading() function:
4590 * node-set set:leading (node-set, node-set)
4591 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4592 * is called.
4593 *
4594 * Returns the nodes in @nodes that precede @node in document order,
4595 * @nodes if @node is NULL or an empty node-set if @nodes
4596 * doesn't contain @node
4597 */
4598xmlNodeSetPtr
4599xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4600 xmlXPathNodeSetSort(nodes);
4601 return(xmlXPathNodeLeadingSorted(nodes, node));
4602}
4603
4604/**
4605 * xmlXPathLeadingSorted:
4606 * @nodes1: a node-set, sorted by document order
4607 * @nodes2: a node-set, sorted by document order
4608 *
4609 * Implements the EXSLT - Sets leading() function:
4610 * node-set set:leading (node-set, node-set)
4611 *
4612 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4613 * in document order, @nodes1 if @nodes2 is NULL or empty or
4614 * an empty node-set if @nodes1 doesn't contain @nodes2
4615 */
4616xmlNodeSetPtr
4617xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4618 if (xmlXPathNodeSetIsEmpty(nodes2))
4619 return(nodes1);
4620 return(xmlXPathNodeLeadingSorted(nodes1,
4621 xmlXPathNodeSetItem(nodes2, 1)));
4622}
4623
4624/**
4625 * xmlXPathLeading:
4626 * @nodes1: a node-set
4627 * @nodes2: a node-set
4628 *
4629 * Implements the EXSLT - Sets leading() function:
4630 * node-set set:leading (node-set, node-set)
4631 * @nodes1 and @nodes2 are sorted by document order, then
4632 * #exslSetsLeadingSorted is called.
4633 *
4634 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4635 * in document order, @nodes1 if @nodes2 is NULL or empty or
4636 * an empty node-set if @nodes1 doesn't contain @nodes2
4637 */
4638xmlNodeSetPtr
4639xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4640 if (xmlXPathNodeSetIsEmpty(nodes2))
4641 return(nodes1);
4642 if (xmlXPathNodeSetIsEmpty(nodes1))
4643 return(xmlXPathNodeSetCreate(NULL));
4644 xmlXPathNodeSetSort(nodes1);
4645 xmlXPathNodeSetSort(nodes2);
4646 return(xmlXPathNodeLeadingSorted(nodes1,
4647 xmlXPathNodeSetItem(nodes2, 1)));
4648}
4649
4650/**
4651 * xmlXPathNodeTrailingSorted:
4652 * @nodes: a node-set, sorted by document order
4653 * @node: a node
4654 *
4655 * Implements the EXSLT - Sets trailing() function:
4656 * node-set set:trailing (node-set, node-set)
4657 *
4658 * Returns the nodes in @nodes that follow @node in document order,
4659 * @nodes if @node is NULL or an empty node-set if @nodes
4660 * doesn't contain @node
4661 */
4662xmlNodeSetPtr
4663xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4664 int i, l;
4665 xmlNodePtr cur;
4666 xmlNodeSetPtr ret;
4667
4668 if (node == NULL)
4669 return(nodes);
4670
4671 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00004672 if (ret == NULL)
4673 return(ret);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004674 if (xmlXPathNodeSetIsEmpty(nodes) ||
4675 (!xmlXPathNodeSetContains(nodes, node)))
4676 return(ret);
4677
4678 l = xmlXPathNodeSetGetLength(nodes);
William M. Brack97ac8192007-06-06 17:19:24 +00004679 for (i = l - 1; i >= 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004680 cur = xmlXPathNodeSetItem(nodes, i);
4681 if (cur == node)
4682 break;
4683 xmlXPathNodeSetAddUnique(ret, cur);
4684 }
William M. Brack97ac8192007-06-06 17:19:24 +00004685 xmlXPathNodeSetSort(ret); /* bug 413451 */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004686 return(ret);
4687}
4688
4689/**
4690 * xmlXPathNodeTrailing:
4691 * @nodes: a node-set
4692 * @node: a node
4693 *
4694 * Implements the EXSLT - Sets trailing() function:
4695 * node-set set:trailing (node-set, node-set)
4696 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4697 * is called.
4698 *
4699 * Returns the nodes in @nodes that follow @node in document order,
4700 * @nodes if @node is NULL or an empty node-set if @nodes
4701 * doesn't contain @node
4702 */
4703xmlNodeSetPtr
4704xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4705 xmlXPathNodeSetSort(nodes);
4706 return(xmlXPathNodeTrailingSorted(nodes, node));
4707}
4708
4709/**
4710 * xmlXPathTrailingSorted:
4711 * @nodes1: a node-set, sorted by document order
4712 * @nodes2: a node-set, sorted by document order
4713 *
4714 * Implements the EXSLT - Sets trailing() function:
4715 * node-set set:trailing (node-set, node-set)
4716 *
4717 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4718 * in document order, @nodes1 if @nodes2 is NULL or empty or
4719 * an empty node-set if @nodes1 doesn't contain @nodes2
4720 */
4721xmlNodeSetPtr
4722xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4723 if (xmlXPathNodeSetIsEmpty(nodes2))
4724 return(nodes1);
4725 return(xmlXPathNodeTrailingSorted(nodes1,
4726 xmlXPathNodeSetItem(nodes2, 0)));
4727}
4728
4729/**
4730 * xmlXPathTrailing:
4731 * @nodes1: a node-set
4732 * @nodes2: a node-set
4733 *
4734 * Implements the EXSLT - Sets trailing() function:
4735 * node-set set:trailing (node-set, node-set)
4736 * @nodes1 and @nodes2 are sorted by document order, then
4737 * #xmlXPathTrailingSorted is called.
4738 *
4739 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4740 * in document order, @nodes1 if @nodes2 is NULL or empty or
4741 * an empty node-set if @nodes1 doesn't contain @nodes2
4742 */
4743xmlNodeSetPtr
4744xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4745 if (xmlXPathNodeSetIsEmpty(nodes2))
4746 return(nodes1);
4747 if (xmlXPathNodeSetIsEmpty(nodes1))
4748 return(xmlXPathNodeSetCreate(NULL));
4749 xmlXPathNodeSetSort(nodes1);
4750 xmlXPathNodeSetSort(nodes2);
4751 return(xmlXPathNodeTrailingSorted(nodes1,
4752 xmlXPathNodeSetItem(nodes2, 0)));
4753}
4754
Owen Taylor3473f882001-02-23 17:55:21 +00004755/************************************************************************
4756 * *
4757 * Routines to handle extra functions *
4758 * *
4759 ************************************************************************/
4760
4761/**
4762 * xmlXPathRegisterFunc:
4763 * @ctxt: the XPath context
4764 * @name: the function name
4765 * @f: the function implementation or NULL
4766 *
4767 * Register a new function. If @f is NULL it unregisters the function
4768 *
4769 * Returns 0 in case of success, -1 in case of error
4770 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00004771int
Owen Taylor3473f882001-02-23 17:55:21 +00004772xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4773 xmlXPathFunction f) {
4774 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4775}
4776
4777/**
4778 * xmlXPathRegisterFuncNS:
4779 * @ctxt: the XPath context
4780 * @name: the function name
4781 * @ns_uri: the function namespace URI
4782 * @f: the function implementation or NULL
4783 *
4784 * Register a new function. If @f is NULL it unregisters the function
4785 *
4786 * Returns 0 in case of success, -1 in case of error
4787 */
4788int
4789xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4790 const xmlChar *ns_uri, xmlXPathFunction f) {
4791 if (ctxt == NULL)
4792 return(-1);
4793 if (name == NULL)
4794 return(-1);
4795
4796 if (ctxt->funcHash == NULL)
4797 ctxt->funcHash = xmlHashCreate(0);
4798 if (ctxt->funcHash == NULL)
4799 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004800 if (f == NULL)
4801 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
William M. Brackad0e67c2004-12-01 14:35:10 +00004802 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
Owen Taylor3473f882001-02-23 17:55:21 +00004803}
4804
4805/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00004806 * xmlXPathRegisterFuncLookup:
4807 * @ctxt: the XPath context
4808 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004809 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00004810 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004811 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00004812 */
4813void
4814xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4815 xmlXPathFuncLookupFunc f,
4816 void *funcCtxt) {
4817 if (ctxt == NULL)
4818 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004819 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004820 ctxt->funcLookupData = funcCtxt;
4821}
4822
4823/**
Owen Taylor3473f882001-02-23 17:55:21 +00004824 * xmlXPathFunctionLookup:
4825 * @ctxt: the XPath context
4826 * @name: the function name
4827 *
4828 * Search in the Function array of the context for the given
4829 * function.
4830 *
4831 * Returns the xmlXPathFunction or NULL if not found
4832 */
4833xmlXPathFunction
4834xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00004835 if (ctxt == NULL)
4836 return (NULL);
4837
4838 if (ctxt->funcLookupFunc != NULL) {
4839 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004840 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004841
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004842 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004843 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004844 if (ret != NULL)
4845 return(ret);
4846 }
Owen Taylor3473f882001-02-23 17:55:21 +00004847 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4848}
4849
4850/**
4851 * xmlXPathFunctionLookupNS:
4852 * @ctxt: the XPath context
4853 * @name: the function name
4854 * @ns_uri: the function namespace URI
4855 *
4856 * Search in the Function array of the context for the given
4857 * function.
4858 *
4859 * Returns the xmlXPathFunction or NULL if not found
4860 */
4861xmlXPathFunction
4862xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4863 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00004864 xmlXPathFunction ret;
Daniel Veillard45490ae2008-07-29 09:13:19 +00004865
Owen Taylor3473f882001-02-23 17:55:21 +00004866 if (ctxt == NULL)
4867 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004868 if (name == NULL)
4869 return(NULL);
4870
Thomas Broyerba4ad322001-07-26 16:55:21 +00004871 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004872 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004873
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004874 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004875 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004876 if (ret != NULL)
4877 return(ret);
4878 }
4879
4880 if (ctxt->funcHash == NULL)
4881 return(NULL);
4882
William M. Brackad0e67c2004-12-01 14:35:10 +00004883 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4884 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004885}
4886
4887/**
4888 * xmlXPathRegisteredFuncsCleanup:
4889 * @ctxt: the XPath context
4890 *
4891 * Cleanup the XPath context data associated to registered functions
4892 */
4893void
4894xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4895 if (ctxt == NULL)
4896 return;
4897
4898 xmlHashFree(ctxt->funcHash, NULL);
4899 ctxt->funcHash = NULL;
4900}
4901
4902/************************************************************************
4903 * *
William M. Brack08171912003-12-29 02:52:11 +00004904 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00004905 * *
4906 ************************************************************************/
4907
4908/**
4909 * xmlXPathRegisterVariable:
4910 * @ctxt: the XPath context
4911 * @name: the variable name
4912 * @value: the variable value or NULL
4913 *
4914 * Register a new variable value. If @value is NULL it unregisters
4915 * the variable
4916 *
4917 * Returns 0 in case of success, -1 in case of error
4918 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00004919int
Owen Taylor3473f882001-02-23 17:55:21 +00004920xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4921 xmlXPathObjectPtr value) {
4922 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4923}
4924
4925/**
4926 * xmlXPathRegisterVariableNS:
4927 * @ctxt: the XPath context
4928 * @name: the variable name
4929 * @ns_uri: the variable namespace URI
4930 * @value: the variable value or NULL
4931 *
4932 * Register a new variable value. If @value is NULL it unregisters
4933 * the variable
4934 *
4935 * Returns 0 in case of success, -1 in case of error
4936 */
4937int
4938xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4939 const xmlChar *ns_uri,
4940 xmlXPathObjectPtr value) {
4941 if (ctxt == NULL)
4942 return(-1);
4943 if (name == NULL)
4944 return(-1);
4945
4946 if (ctxt->varHash == NULL)
4947 ctxt->varHash = xmlHashCreate(0);
4948 if (ctxt->varHash == NULL)
4949 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004950 if (value == NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00004951 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
Daniel Veillard94394cd2003-10-29 17:07:51 +00004952 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00004953 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4954 (void *) value,
4955 (xmlHashDeallocator)xmlXPathFreeObject));
4956}
4957
4958/**
4959 * xmlXPathRegisterVariableLookup:
4960 * @ctxt: the XPath context
4961 * @f: the lookup function
4962 * @data: the lookup data
4963 *
4964 * register an external mechanism to do variable lookup
4965 */
4966void
4967xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4968 xmlXPathVariableLookupFunc f, void *data) {
4969 if (ctxt == NULL)
4970 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004971 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00004972 ctxt->varLookupData = data;
4973}
4974
4975/**
4976 * xmlXPathVariableLookup:
4977 * @ctxt: the XPath context
4978 * @name: the variable name
4979 *
4980 * Search in the Variable array of the context for the given
4981 * variable value.
4982 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00004983 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00004984 */
4985xmlXPathObjectPtr
4986xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4987 if (ctxt == NULL)
4988 return(NULL);
4989
4990 if (ctxt->varLookupFunc != NULL) {
4991 xmlXPathObjectPtr ret;
4992
4993 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4994 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00004995 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004996 }
4997 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4998}
4999
5000/**
5001 * xmlXPathVariableLookupNS:
5002 * @ctxt: the XPath context
5003 * @name: the variable name
5004 * @ns_uri: the variable namespace URI
5005 *
5006 * Search in the Variable array of the context for the given
Daniel Veillard45490ae2008-07-29 09:13:19 +00005007 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00005008 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00005009 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00005010 */
5011xmlXPathObjectPtr
5012xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5013 const xmlChar *ns_uri) {
5014 if (ctxt == NULL)
5015 return(NULL);
5016
5017 if (ctxt->varLookupFunc != NULL) {
5018 xmlXPathObjectPtr ret;
5019
5020 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5021 (ctxt->varLookupData, name, ns_uri);
5022 if (ret != NULL) return(ret);
5023 }
5024
5025 if (ctxt->varHash == NULL)
5026 return(NULL);
5027 if (name == NULL)
5028 return(NULL);
5029
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005030 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
Daniel Veillard8c357d52001-07-03 23:43:33 +00005031 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00005032}
5033
5034/**
5035 * xmlXPathRegisteredVariablesCleanup:
5036 * @ctxt: the XPath context
5037 *
5038 * Cleanup the XPath context data associated to registered variables
5039 */
5040void
5041xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5042 if (ctxt == NULL)
5043 return;
5044
Daniel Veillard76d66f42001-05-16 21:05:17 +00005045 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00005046 ctxt->varHash = NULL;
5047}
5048
5049/**
5050 * xmlXPathRegisterNs:
5051 * @ctxt: the XPath context
Daniel Veillarddb3ce962009-03-25 09:43:49 +00005052 * @prefix: the namespace prefix cannot be NULL or empty string
Owen Taylor3473f882001-02-23 17:55:21 +00005053 * @ns_uri: the namespace name
5054 *
5055 * Register a new namespace. If @ns_uri is NULL it unregisters
5056 * the namespace
5057 *
5058 * Returns 0 in case of success, -1 in case of error
5059 */
5060int
5061xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5062 const xmlChar *ns_uri) {
5063 if (ctxt == NULL)
5064 return(-1);
5065 if (prefix == NULL)
5066 return(-1);
Daniel Veillarddb3ce962009-03-25 09:43:49 +00005067 if (prefix[0] == 0)
5068 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00005069
5070 if (ctxt->nsHash == NULL)
5071 ctxt->nsHash = xmlHashCreate(10);
5072 if (ctxt->nsHash == NULL)
5073 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00005074 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00005075 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00005076 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00005077 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00005078 (xmlHashDeallocator)xmlFree));
5079}
5080
5081/**
5082 * xmlXPathNsLookup:
5083 * @ctxt: the XPath context
5084 * @prefix: the namespace prefix value
5085 *
5086 * Search in the namespace declaration array of the context for the given
5087 * namespace name associated to the given prefix
5088 *
5089 * Returns the value or NULL if not found
5090 */
5091const xmlChar *
5092xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5093 if (ctxt == NULL)
5094 return(NULL);
5095 if (prefix == NULL)
5096 return(NULL);
5097
5098#ifdef XML_XML_NAMESPACE
5099 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5100 return(XML_XML_NAMESPACE);
5101#endif
5102
Daniel Veillardc8f620b2001-04-30 20:31:33 +00005103 if (ctxt->namespaces != NULL) {
5104 int i;
5105
5106 for (i = 0;i < ctxt->nsNr;i++) {
5107 if ((ctxt->namespaces[i] != NULL) &&
5108 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5109 return(ctxt->namespaces[i]->href);
5110 }
5111 }
Owen Taylor3473f882001-02-23 17:55:21 +00005112
5113 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5114}
5115
5116/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005117 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00005118 * @ctxt: the XPath context
5119 *
5120 * Cleanup the XPath context data associated to registered variables
5121 */
5122void
5123xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5124 if (ctxt == NULL)
5125 return;
5126
Daniel Veillard42766c02002-08-22 20:52:17 +00005127 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00005128 ctxt->nsHash = NULL;
5129}
5130
5131/************************************************************************
5132 * *
5133 * Routines to handle Values *
5134 * *
5135 ************************************************************************/
5136
William M. Brack08171912003-12-29 02:52:11 +00005137/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005138
5139/**
5140 * xmlXPathNewFloat:
5141 * @val: the double value
5142 *
5143 * Create a new xmlXPathObjectPtr of type double and of value @val
5144 *
5145 * Returns the newly created object.
5146 */
5147xmlXPathObjectPtr
5148xmlXPathNewFloat(double val) {
5149 xmlXPathObjectPtr ret;
5150
5151 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5152 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005153 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005154 return(NULL);
5155 }
5156 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5157 ret->type = XPATH_NUMBER;
5158 ret->floatval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005159#ifdef XP_DEBUG_OBJ_USAGE
5160 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5161#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005162 return(ret);
5163}
5164
5165/**
5166 * xmlXPathNewBoolean:
5167 * @val: the boolean value
5168 *
5169 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5170 *
5171 * Returns the newly created object.
5172 */
5173xmlXPathObjectPtr
5174xmlXPathNewBoolean(int val) {
5175 xmlXPathObjectPtr ret;
5176
5177 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5178 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005179 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005180 return(NULL);
5181 }
5182 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5183 ret->type = XPATH_BOOLEAN;
5184 ret->boolval = (val != 0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005185#ifdef XP_DEBUG_OBJ_USAGE
5186 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5187#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005188 return(ret);
5189}
5190
5191/**
5192 * xmlXPathNewString:
5193 * @val: the xmlChar * value
5194 *
5195 * Create a new xmlXPathObjectPtr of type string and of value @val
5196 *
5197 * Returns the newly created object.
5198 */
5199xmlXPathObjectPtr
5200xmlXPathNewString(const xmlChar *val) {
5201 xmlXPathObjectPtr ret;
5202
5203 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5204 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005205 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005206 return(NULL);
5207 }
5208 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5209 ret->type = XPATH_STRING;
5210 if (val != NULL)
5211 ret->stringval = xmlStrdup(val);
5212 else
5213 ret->stringval = xmlStrdup((const xmlChar *)"");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005214#ifdef XP_DEBUG_OBJ_USAGE
5215 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5216#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005217 return(ret);
5218}
5219
5220/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005221 * xmlXPathWrapString:
5222 * @val: the xmlChar * value
5223 *
5224 * Wraps the @val string into an XPath object.
5225 *
5226 * Returns the newly created object.
5227 */
5228xmlXPathObjectPtr
5229xmlXPathWrapString (xmlChar *val) {
5230 xmlXPathObjectPtr ret;
5231
5232 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5233 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005234 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005235 return(NULL);
5236 }
5237 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5238 ret->type = XPATH_STRING;
5239 ret->stringval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005240#ifdef XP_DEBUG_OBJ_USAGE
5241 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5242#endif
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005243 return(ret);
5244}
5245
5246/**
Owen Taylor3473f882001-02-23 17:55:21 +00005247 * xmlXPathNewCString:
5248 * @val: the char * value
5249 *
5250 * Create a new xmlXPathObjectPtr of type string and of value @val
5251 *
5252 * Returns the newly created object.
5253 */
5254xmlXPathObjectPtr
5255xmlXPathNewCString(const char *val) {
5256 xmlXPathObjectPtr ret;
5257
5258 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5259 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005260 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005261 return(NULL);
5262 }
5263 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5264 ret->type = XPATH_STRING;
5265 ret->stringval = xmlStrdup(BAD_CAST val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005266#ifdef XP_DEBUG_OBJ_USAGE
5267 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5268#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005269 return(ret);
5270}
5271
5272/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005273 * xmlXPathWrapCString:
5274 * @val: the char * value
5275 *
5276 * Wraps a string into an XPath object.
5277 *
5278 * Returns the newly created object.
5279 */
5280xmlXPathObjectPtr
5281xmlXPathWrapCString (char * val) {
5282 return(xmlXPathWrapString((xmlChar *)(val)));
5283}
5284
5285/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005286 * xmlXPathWrapExternal:
5287 * @val: the user data
5288 *
5289 * Wraps the @val data into an XPath object.
5290 *
5291 * Returns the newly created object.
5292 */
5293xmlXPathObjectPtr
5294xmlXPathWrapExternal (void *val) {
5295 xmlXPathObjectPtr ret;
5296
5297 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5298 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005299 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005300 return(NULL);
5301 }
5302 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5303 ret->type = XPATH_USERS;
5304 ret->user = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005305#ifdef XP_DEBUG_OBJ_USAGE
5306 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5307#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005308 return(ret);
5309}
5310
5311/**
Owen Taylor3473f882001-02-23 17:55:21 +00005312 * xmlXPathObjectCopy:
5313 * @val: the original object
5314 *
5315 * allocate a new copy of a given object
5316 *
5317 * Returns the newly created object.
5318 */
5319xmlXPathObjectPtr
5320xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5321 xmlXPathObjectPtr ret;
5322
5323 if (val == NULL)
5324 return(NULL);
5325
5326 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5327 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005328 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005329 return(NULL);
5330 }
5331 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005332#ifdef XP_DEBUG_OBJ_USAGE
5333 xmlXPathDebugObjUsageRequested(NULL, val->type);
5334#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005335 switch (val->type) {
5336 case XPATH_BOOLEAN:
5337 case XPATH_NUMBER:
5338 case XPATH_POINT:
5339 case XPATH_RANGE:
5340 break;
5341 case XPATH_STRING:
5342 ret->stringval = xmlStrdup(val->stringval);
5343 break;
5344 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00005345#if 0
5346/*
5347 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5348 this previous handling is no longer correct, and can cause some serious
5349 problems (ref. bug 145547)
5350*/
Owen Taylor3473f882001-02-23 17:55:21 +00005351 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005352 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005353 xmlNodePtr cur, tmp;
5354 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005355
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005356 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005357 top = xmlNewDoc(NULL);
5358 top->name = (char *)
5359 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005360 ret->user = top;
5361 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005362 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005363 cur = val->nodesetval->nodeTab[0]->children;
5364 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005365 tmp = xmlDocCopyNode(cur, top, 1);
5366 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005367 cur = cur->next;
5368 }
5369 }
William M. Bracke9449c52004-07-11 14:41:20 +00005370
Daniel Veillard9adc0462003-03-24 18:39:54 +00005371 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005372 } else
Owen Taylor3473f882001-02-23 17:55:21 +00005373 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005374 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00005375 break;
William M. Bracke9449c52004-07-11 14:41:20 +00005376#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005377 case XPATH_NODESET:
5378 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005379 /* Do not deallocate the copied tree value */
5380 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005381 break;
5382 case XPATH_LOCATIONSET:
5383#ifdef LIBXML_XPTR_ENABLED
5384 {
5385 xmlLocationSetPtr loc = val->user;
5386 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5387 break;
5388 }
5389#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00005390 case XPATH_USERS:
5391 ret->user = val->user;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005392 break;
Thomas Broyer47334c02001-10-07 16:41:52 +00005393 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00005394 xmlGenericError(xmlGenericErrorContext,
5395 "xmlXPathObjectCopy: unsupported type %d\n",
5396 val->type);
5397 break;
5398 }
5399 return(ret);
5400}
5401
5402/**
5403 * xmlXPathFreeObject:
5404 * @obj: the object to free
5405 *
5406 * Free up an xmlXPathObjectPtr object.
5407 */
5408void
5409xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5410 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005411 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00005412 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00005413#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005414 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005415 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00005416 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00005417 } else
5418#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005419 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
William M. Bracke9449c52004-07-11 14:41:20 +00005420 if (obj->nodesetval != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +00005421 xmlXPathFreeValueTree(obj->nodesetval);
Daniel Veillard77851712001-02-27 21:54:07 +00005422 } else {
5423 if (obj->nodesetval != NULL)
5424 xmlXPathFreeNodeSet(obj->nodesetval);
5425 }
Owen Taylor3473f882001-02-23 17:55:21 +00005426#ifdef LIBXML_XPTR_ENABLED
5427 } else if (obj->type == XPATH_LOCATIONSET) {
5428 if (obj->user != NULL)
5429 xmlXPtrFreeLocationSet(obj->user);
5430#endif
5431 } else if (obj->type == XPATH_STRING) {
5432 if (obj->stringval != NULL)
5433 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005434 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005435#ifdef XP_DEBUG_OBJ_USAGE
5436 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5437#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00005438 xmlFree(obj);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005439}
Owen Taylor3473f882001-02-23 17:55:21 +00005440
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005441/**
5442 * xmlXPathReleaseObject:
5443 * @obj: the xmlXPathObjectPtr to free or to cache
5444 *
5445 * Depending on the state of the cache this frees the given
5446 * XPath object or stores it in the cache.
5447 */
5448static void
5449xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5450{
5451#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5452 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5453 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5454
5455#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5456
5457 if (obj == NULL)
5458 return;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005459 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005460 xmlXPathFreeObject(obj);
Daniel Veillard45490ae2008-07-29 09:13:19 +00005461 } else {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005462 xmlXPathContextCachePtr cache =
5463 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005464
5465 switch (obj->type) {
5466 case XPATH_NODESET:
5467 case XPATH_XSLT_TREE:
5468 if (obj->nodesetval != NULL) {
5469 if (obj->boolval) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00005470 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005471 * It looks like the @boolval is used for
5472 * evaluation if this an XSLT Result Tree Fragment.
5473 * TODO: Check if this assumption is correct.
5474 */
5475 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5476 xmlXPathFreeValueTree(obj->nodesetval);
5477 obj->nodesetval = NULL;
5478 } else if ((obj->nodesetval->nodeMax <= 40) &&
5479 (XP_CACHE_WANTS(cache->nodesetObjs,
5480 cache->maxNodeset)))
5481 {
5482 XP_CACHE_ADD(cache->nodesetObjs, obj);
5483 goto obj_cached;
5484 } else {
5485 xmlXPathFreeNodeSet(obj->nodesetval);
5486 obj->nodesetval = NULL;
5487 }
5488 }
5489 break;
5490 case XPATH_STRING:
5491 if (obj->stringval != NULL)
5492 xmlFree(obj->stringval);
5493
5494 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5495 XP_CACHE_ADD(cache->stringObjs, obj);
5496 goto obj_cached;
5497 }
5498 break;
5499 case XPATH_BOOLEAN:
5500 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5501 XP_CACHE_ADD(cache->booleanObjs, obj);
5502 goto obj_cached;
5503 }
5504 break;
5505 case XPATH_NUMBER:
5506 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5507 XP_CACHE_ADD(cache->numberObjs, obj);
5508 goto obj_cached;
5509 }
5510 break;
5511#ifdef LIBXML_XPTR_ENABLED
5512 case XPATH_LOCATIONSET:
5513 if (obj->user != NULL) {
5514 xmlXPtrFreeLocationSet(obj->user);
5515 }
5516 goto free_obj;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005517#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005518 default:
5519 goto free_obj;
5520 }
5521
5522 /*
5523 * Fallback to adding to the misc-objects slot.
5524 */
5525 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5526 XP_CACHE_ADD(cache->miscObjs, obj);
5527 } else
5528 goto free_obj;
5529
5530obj_cached:
5531
5532#ifdef XP_DEBUG_OBJ_USAGE
5533 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5534#endif
5535
5536 if (obj->nodesetval != NULL) {
5537 xmlNodeSetPtr tmpset = obj->nodesetval;
Daniel Veillard45490ae2008-07-29 09:13:19 +00005538
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005539 /*
5540 * TODO: Due to those nasty ns-nodes, we need to traverse
5541 * the list and free the ns-nodes.
5542 * URGENT TODO: Check if it's actually slowing things down.
5543 * Maybe we shouldn't try to preserve the list.
5544 */
5545 if (tmpset->nodeNr > 1) {
5546 int i;
5547 xmlNodePtr node;
5548
5549 for (i = 0; i < tmpset->nodeNr; i++) {
5550 node = tmpset->nodeTab[i];
5551 if ((node != NULL) &&
5552 (node->type == XML_NAMESPACE_DECL))
5553 {
5554 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5555 }
5556 }
5557 } else if (tmpset->nodeNr == 1) {
5558 if ((tmpset->nodeTab[0] != NULL) &&
5559 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5560 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
Daniel Veillard45490ae2008-07-29 09:13:19 +00005561 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005562 tmpset->nodeNr = 0;
5563 memset(obj, 0, sizeof(xmlXPathObject));
5564 obj->nodesetval = tmpset;
5565 } else
5566 memset(obj, 0, sizeof(xmlXPathObject));
5567
5568 return;
5569
5570free_obj:
5571 /*
5572 * Cache is full; free the object.
Daniel Veillard45490ae2008-07-29 09:13:19 +00005573 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005574 if (obj->nodesetval != NULL)
5575 xmlXPathFreeNodeSet(obj->nodesetval);
5576#ifdef XP_DEBUG_OBJ_USAGE
5577 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5578#endif
5579 xmlFree(obj);
5580 }
5581 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005582}
5583
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005584
5585/************************************************************************
5586 * *
5587 * Type Casting Routines *
5588 * *
5589 ************************************************************************/
5590
5591/**
5592 * xmlXPathCastBooleanToString:
5593 * @val: a boolean
5594 *
5595 * Converts a boolean to its string value.
5596 *
5597 * Returns a newly allocated string.
5598 */
5599xmlChar *
5600xmlXPathCastBooleanToString (int val) {
5601 xmlChar *ret;
5602 if (val)
5603 ret = xmlStrdup((const xmlChar *) "true");
5604 else
5605 ret = xmlStrdup((const xmlChar *) "false");
5606 return(ret);
5607}
5608
5609/**
5610 * xmlXPathCastNumberToString:
5611 * @val: a number
5612 *
5613 * Converts a number to its string value.
5614 *
5615 * Returns a newly allocated string.
5616 */
5617xmlChar *
5618xmlXPathCastNumberToString (double val) {
5619 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00005620 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005621 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005622 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005623 break;
5624 case -1:
5625 ret = xmlStrdup((const xmlChar *) "-Infinity");
5626 break;
5627 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00005628 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005629 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005630 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5631 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005632 } else {
5633 /* could be improved */
5634 char buf[100];
Daniel Veillard11ce4002006-03-10 00:36:23 +00005635 xmlXPathFormatNumber(val, buf, 99);
5636 buf[99] = 0;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005637 ret = xmlStrdup((const xmlChar *) buf);
5638 }
5639 }
5640 return(ret);
5641}
5642
5643/**
5644 * xmlXPathCastNodeToString:
5645 * @node: a node
5646 *
5647 * Converts a node to its string value.
5648 *
5649 * Returns a newly allocated string.
5650 */
5651xmlChar *
5652xmlXPathCastNodeToString (xmlNodePtr node) {
William M. Brackd611c882007-05-31 05:07:17 +00005653xmlChar *ret;
5654 if ((ret = xmlNodeGetContent(node)) == NULL)
5655 ret = xmlStrdup((const xmlChar *) "");
5656 return(ret);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005657}
5658
5659/**
5660 * xmlXPathCastNodeSetToString:
5661 * @ns: a node-set
5662 *
5663 * Converts a node-set to its string value.
5664 *
5665 * Returns a newly allocated string.
5666 */
5667xmlChar *
5668xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5669 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5670 return(xmlStrdup((const xmlChar *) ""));
5671
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00005672 if (ns->nodeNr > 1)
5673 xmlXPathNodeSetSort(ns);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005674 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5675}
5676
5677/**
5678 * xmlXPathCastToString:
5679 * @val: an XPath object
5680 *
5681 * Converts an existing object to its string() equivalent
5682 *
Kasimier T. Buchcik50128ad2006-08-15 13:04:07 +00005683 * Returns the allocated string value of the object, NULL in case of error.
Daniel Veillard45490ae2008-07-29 09:13:19 +00005684 * It's up to the caller to free the string memory with xmlFree().
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005685 */
5686xmlChar *
5687xmlXPathCastToString(xmlXPathObjectPtr val) {
5688 xmlChar *ret = NULL;
5689
5690 if (val == NULL)
5691 return(xmlStrdup((const xmlChar *) ""));
5692 switch (val->type) {
5693 case XPATH_UNDEFINED:
5694#ifdef DEBUG_EXPR
5695 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5696#endif
5697 ret = xmlStrdup((const xmlChar *) "");
5698 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005699 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005700 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005701 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5702 break;
5703 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00005704 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005705 case XPATH_BOOLEAN:
5706 ret = xmlXPathCastBooleanToString(val->boolval);
5707 break;
5708 case XPATH_NUMBER: {
5709 ret = xmlXPathCastNumberToString(val->floatval);
5710 break;
5711 }
5712 case XPATH_USERS:
5713 case XPATH_POINT:
5714 case XPATH_RANGE:
5715 case XPATH_LOCATIONSET:
5716 TODO
5717 ret = xmlStrdup((const xmlChar *) "");
5718 break;
5719 }
5720 return(ret);
5721}
5722
5723/**
5724 * xmlXPathConvertString:
5725 * @val: an XPath object
5726 *
5727 * Converts an existing object to its string() equivalent
5728 *
5729 * Returns the new object, the old one is freed (or the operation
5730 * is done directly on @val)
5731 */
5732xmlXPathObjectPtr
5733xmlXPathConvertString(xmlXPathObjectPtr val) {
5734 xmlChar *res = NULL;
5735
5736 if (val == NULL)
5737 return(xmlXPathNewCString(""));
5738
5739 switch (val->type) {
5740 case XPATH_UNDEFINED:
5741#ifdef DEBUG_EXPR
5742 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5743#endif
5744 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005745 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005746 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005747 res = xmlXPathCastNodeSetToString(val->nodesetval);
5748 break;
5749 case XPATH_STRING:
5750 return(val);
5751 case XPATH_BOOLEAN:
5752 res = xmlXPathCastBooleanToString(val->boolval);
5753 break;
5754 case XPATH_NUMBER:
5755 res = xmlXPathCastNumberToString(val->floatval);
5756 break;
5757 case XPATH_USERS:
5758 case XPATH_POINT:
5759 case XPATH_RANGE:
5760 case XPATH_LOCATIONSET:
5761 TODO;
5762 break;
5763 }
5764 xmlXPathFreeObject(val);
5765 if (res == NULL)
5766 return(xmlXPathNewCString(""));
5767 return(xmlXPathWrapString(res));
5768}
5769
5770/**
5771 * xmlXPathCastBooleanToNumber:
5772 * @val: a boolean
5773 *
5774 * Converts a boolean to its number value
5775 *
5776 * Returns the number value
5777 */
5778double
5779xmlXPathCastBooleanToNumber(int val) {
5780 if (val)
5781 return(1.0);
5782 return(0.0);
5783}
5784
5785/**
5786 * xmlXPathCastStringToNumber:
5787 * @val: a string
5788 *
5789 * Converts a string to its number value
5790 *
5791 * Returns the number value
5792 */
5793double
5794xmlXPathCastStringToNumber(const xmlChar * val) {
5795 return(xmlXPathStringEvalNumber(val));
5796}
5797
5798/**
5799 * xmlXPathCastNodeToNumber:
5800 * @node: a node
5801 *
5802 * Converts a node to its number value
5803 *
5804 * Returns the number value
5805 */
5806double
5807xmlXPathCastNodeToNumber (xmlNodePtr node) {
5808 xmlChar *strval;
5809 double ret;
5810
5811 if (node == NULL)
5812 return(xmlXPathNAN);
5813 strval = xmlXPathCastNodeToString(node);
5814 if (strval == NULL)
5815 return(xmlXPathNAN);
5816 ret = xmlXPathCastStringToNumber(strval);
5817 xmlFree(strval);
5818
5819 return(ret);
5820}
5821
5822/**
5823 * xmlXPathCastNodeSetToNumber:
5824 * @ns: a node-set
5825 *
5826 * Converts a node-set to its number value
5827 *
5828 * Returns the number value
5829 */
5830double
5831xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5832 xmlChar *str;
5833 double ret;
5834
5835 if (ns == NULL)
5836 return(xmlXPathNAN);
5837 str = xmlXPathCastNodeSetToString(ns);
5838 ret = xmlXPathCastStringToNumber(str);
5839 xmlFree(str);
5840 return(ret);
5841}
5842
5843/**
5844 * xmlXPathCastToNumber:
5845 * @val: an XPath object
5846 *
5847 * Converts an XPath object to its number value
5848 *
5849 * Returns the number value
5850 */
5851double
5852xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5853 double ret = 0.0;
5854
5855 if (val == NULL)
5856 return(xmlXPathNAN);
5857 switch (val->type) {
5858 case XPATH_UNDEFINED:
5859#ifdef DEGUB_EXPR
5860 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5861#endif
5862 ret = xmlXPathNAN;
5863 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005864 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005865 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005866 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5867 break;
5868 case XPATH_STRING:
5869 ret = xmlXPathCastStringToNumber(val->stringval);
5870 break;
5871 case XPATH_NUMBER:
5872 ret = val->floatval;
5873 break;
5874 case XPATH_BOOLEAN:
5875 ret = xmlXPathCastBooleanToNumber(val->boolval);
5876 break;
5877 case XPATH_USERS:
5878 case XPATH_POINT:
5879 case XPATH_RANGE:
5880 case XPATH_LOCATIONSET:
5881 TODO;
5882 ret = xmlXPathNAN;
5883 break;
5884 }
5885 return(ret);
5886}
5887
5888/**
5889 * xmlXPathConvertNumber:
5890 * @val: an XPath object
5891 *
5892 * Converts an existing object to its number() equivalent
5893 *
5894 * Returns the new object, the old one is freed (or the operation
5895 * is done directly on @val)
5896 */
5897xmlXPathObjectPtr
5898xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5899 xmlXPathObjectPtr ret;
5900
5901 if (val == NULL)
5902 return(xmlXPathNewFloat(0.0));
5903 if (val->type == XPATH_NUMBER)
5904 return(val);
5905 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5906 xmlXPathFreeObject(val);
5907 return(ret);
5908}
5909
5910/**
5911 * xmlXPathCastNumberToBoolean:
5912 * @val: a number
5913 *
5914 * Converts a number to its boolean value
5915 *
5916 * Returns the boolean value
5917 */
5918int
5919xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00005920 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005921 return(0);
5922 return(1);
5923}
5924
5925/**
5926 * xmlXPathCastStringToBoolean:
5927 * @val: a string
5928 *
5929 * Converts a string to its boolean value
5930 *
5931 * Returns the boolean value
5932 */
5933int
5934xmlXPathCastStringToBoolean (const xmlChar *val) {
5935 if ((val == NULL) || (xmlStrlen(val) == 0))
5936 return(0);
5937 return(1);
5938}
5939
5940/**
5941 * xmlXPathCastNodeSetToBoolean:
5942 * @ns: a node-set
5943 *
5944 * Converts a node-set to its boolean value
5945 *
5946 * Returns the boolean value
5947 */
5948int
5949xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5950 if ((ns == NULL) || (ns->nodeNr == 0))
5951 return(0);
5952 return(1);
5953}
5954
5955/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005956 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005957 * @val: an XPath object
5958 *
5959 * Converts an XPath object to its boolean value
5960 *
5961 * Returns the boolean value
5962 */
5963int
5964xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5965 int ret = 0;
5966
5967 if (val == NULL)
5968 return(0);
5969 switch (val->type) {
5970 case XPATH_UNDEFINED:
5971#ifdef DEBUG_EXPR
5972 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
5973#endif
5974 ret = 0;
5975 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005976 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005977 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005978 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5979 break;
5980 case XPATH_STRING:
5981 ret = xmlXPathCastStringToBoolean(val->stringval);
5982 break;
5983 case XPATH_NUMBER:
5984 ret = xmlXPathCastNumberToBoolean(val->floatval);
5985 break;
5986 case XPATH_BOOLEAN:
5987 ret = val->boolval;
5988 break;
5989 case XPATH_USERS:
5990 case XPATH_POINT:
5991 case XPATH_RANGE:
5992 case XPATH_LOCATIONSET:
5993 TODO;
5994 ret = 0;
5995 break;
5996 }
5997 return(ret);
5998}
5999
6000
6001/**
6002 * xmlXPathConvertBoolean:
6003 * @val: an XPath object
6004 *
6005 * Converts an existing object to its boolean() equivalent
6006 *
6007 * Returns the new object, the old one is freed (or the operation
6008 * is done directly on @val)
6009 */
6010xmlXPathObjectPtr
6011xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6012 xmlXPathObjectPtr ret;
6013
6014 if (val == NULL)
6015 return(xmlXPathNewBoolean(0));
6016 if (val->type == XPATH_BOOLEAN)
6017 return(val);
6018 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6019 xmlXPathFreeObject(val);
6020 return(ret);
6021}
6022
Owen Taylor3473f882001-02-23 17:55:21 +00006023/************************************************************************
6024 * *
6025 * Routines to handle XPath contexts *
6026 * *
6027 ************************************************************************/
6028
6029/**
6030 * xmlXPathNewContext:
6031 * @doc: the XML document
6032 *
6033 * Create a new xmlXPathContext
6034 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00006035 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00006036 */
6037xmlXPathContextPtr
6038xmlXPathNewContext(xmlDocPtr doc) {
6039 xmlXPathContextPtr ret;
6040
6041 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6042 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006043 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006044 return(NULL);
6045 }
6046 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6047 ret->doc = doc;
6048 ret->node = NULL;
6049
6050 ret->varHash = NULL;
6051
6052 ret->nb_types = 0;
6053 ret->max_types = 0;
6054 ret->types = NULL;
6055
6056 ret->funcHash = xmlHashCreate(0);
6057
6058 ret->nb_axis = 0;
6059 ret->max_axis = 0;
6060 ret->axis = NULL;
6061
6062 ret->nsHash = NULL;
6063 ret->user = NULL;
6064
6065 ret->contextSize = -1;
6066 ret->proximityPosition = -1;
6067
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006068#ifdef XP_DEFAULT_CACHE_ON
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006069 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006070 xmlXPathFreeContext(ret);
6071 return(NULL);
6072 }
6073#endif
6074
Daniel Veillard45490ae2008-07-29 09:13:19 +00006075 xmlXPathRegisterAllFunctions(ret);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006076
Owen Taylor3473f882001-02-23 17:55:21 +00006077 return(ret);
6078}
6079
6080/**
6081 * xmlXPathFreeContext:
6082 * @ctxt: the context to free
6083 *
6084 * Free up an xmlXPathContext
6085 */
6086void
6087xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006088 if (ctxt == NULL) return;
6089
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006090 if (ctxt->cache != NULL)
6091 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
Owen Taylor3473f882001-02-23 17:55:21 +00006092 xmlXPathRegisteredNsCleanup(ctxt);
6093 xmlXPathRegisteredFuncsCleanup(ctxt);
6094 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006095 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00006096 xmlFree(ctxt);
6097}
6098
6099/************************************************************************
6100 * *
6101 * Routines to handle XPath parser contexts *
6102 * *
6103 ************************************************************************/
6104
6105#define CHECK_CTXT(ctxt) \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006106 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00006107 __xmlRaiseError(NULL, NULL, NULL, \
6108 NULL, NULL, XML_FROM_XPATH, \
6109 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6110 __FILE__, __LINE__, \
6111 NULL, NULL, NULL, 0, 0, \
6112 "NULL context pointer\n"); \
6113 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00006114 } \
6115
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006116#define CHECK_CTXT_NEG(ctxt) \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006117 if (ctxt == NULL) { \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006118 __xmlRaiseError(NULL, NULL, NULL, \
6119 NULL, NULL, XML_FROM_XPATH, \
6120 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6121 __FILE__, __LINE__, \
6122 NULL, NULL, NULL, 0, 0, \
6123 "NULL context pointer\n"); \
6124 return(-1); \
6125 } \
6126
Owen Taylor3473f882001-02-23 17:55:21 +00006127
6128#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00006129 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
Daniel Veillard45490ae2008-07-29 09:13:19 +00006130 (ctxt->doc->children == NULL)) { \
Daniel Veillard57b25162004-11-06 14:50:18 +00006131 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00006132 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00006133 }
Owen Taylor3473f882001-02-23 17:55:21 +00006134
6135
6136/**
6137 * xmlXPathNewParserContext:
6138 * @str: the XPath expression
6139 * @ctxt: the XPath context
6140 *
6141 * Create a new xmlXPathParserContext
6142 *
6143 * Returns the xmlXPathParserContext just allocated.
6144 */
6145xmlXPathParserContextPtr
6146xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6147 xmlXPathParserContextPtr ret;
6148
6149 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6150 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006151 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006152 return(NULL);
6153 }
6154 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6155 ret->cur = ret->base = str;
6156 ret->context = ctxt;
6157
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006158 ret->comp = xmlXPathNewCompExpr();
6159 if (ret->comp == NULL) {
6160 xmlFree(ret->valueTab);
6161 xmlFree(ret);
6162 return(NULL);
6163 }
Daniel Veillard4773df22004-01-23 13:15:13 +00006164 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6165 ret->comp->dict = ctxt->dict;
6166 xmlDictReference(ret->comp->dict);
6167 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006168
6169 return(ret);
6170}
6171
6172/**
6173 * xmlXPathCompParserContext:
6174 * @comp: the XPath compiled expression
6175 * @ctxt: the XPath context
6176 *
6177 * Create a new xmlXPathParserContext when processing a compiled expression
6178 *
6179 * Returns the xmlXPathParserContext just allocated.
6180 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006181static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006182xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6183 xmlXPathParserContextPtr ret;
6184
6185 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6186 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006187 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006188 return(NULL);
6189 }
6190 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6191
Owen Taylor3473f882001-02-23 17:55:21 +00006192 /* Allocate the value stack */
Daniel Veillard45490ae2008-07-29 09:13:19 +00006193 ret->valueTab = (xmlXPathObjectPtr *)
Owen Taylor3473f882001-02-23 17:55:21 +00006194 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006195 if (ret->valueTab == NULL) {
6196 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006197 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006198 return(NULL);
6199 }
Owen Taylor3473f882001-02-23 17:55:21 +00006200 ret->valueNr = 0;
6201 ret->valueMax = 10;
6202 ret->value = NULL;
Daniel Veillardf5048b32011-08-18 17:10:13 +08006203 ret->valueFrame = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006204
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006205 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006206 ret->comp = comp;
6207
Owen Taylor3473f882001-02-23 17:55:21 +00006208 return(ret);
6209}
6210
6211/**
6212 * xmlXPathFreeParserContext:
6213 * @ctxt: the context to free
6214 *
6215 * Free up an xmlXPathParserContext
6216 */
6217void
6218xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6219 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006220 xmlFree(ctxt->valueTab);
6221 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00006222 if (ctxt->comp != NULL) {
6223#ifdef XPATH_STREAMING
6224 if (ctxt->comp->stream != NULL) {
6225 xmlFreePatternList(ctxt->comp->stream);
6226 ctxt->comp->stream = NULL;
6227 }
6228#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006229 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard56de87e2005-02-16 00:22:29 +00006230 }
Owen Taylor3473f882001-02-23 17:55:21 +00006231 xmlFree(ctxt);
6232}
6233
6234/************************************************************************
6235 * *
6236 * The implicit core function library *
6237 * *
6238 ************************************************************************/
6239
Owen Taylor3473f882001-02-23 17:55:21 +00006240/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006241 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00006242 * @node: a node pointer
6243 *
6244 * Function computing the beginning of the string value of the node,
6245 * used to speed up comparisons
6246 *
6247 * Returns an int usable as a hash
6248 */
6249static unsigned int
6250xmlXPathNodeValHash(xmlNodePtr node) {
6251 int len = 2;
6252 const xmlChar * string = NULL;
6253 xmlNodePtr tmp = NULL;
6254 unsigned int ret = 0;
6255
6256 if (node == NULL)
6257 return(0);
6258
Daniel Veillard9adc0462003-03-24 18:39:54 +00006259 if (node->type == XML_DOCUMENT_NODE) {
6260 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6261 if (tmp == NULL)
6262 node = node->children;
6263 else
6264 node = tmp;
6265
6266 if (node == NULL)
6267 return(0);
6268 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006269
6270 switch (node->type) {
6271 case XML_COMMENT_NODE:
6272 case XML_PI_NODE:
6273 case XML_CDATA_SECTION_NODE:
6274 case XML_TEXT_NODE:
6275 string = node->content;
6276 if (string == NULL)
6277 return(0);
6278 if (string[0] == 0)
6279 return(0);
6280 return(((unsigned int) string[0]) +
6281 (((unsigned int) string[1]) << 8));
6282 case XML_NAMESPACE_DECL:
6283 string = ((xmlNsPtr)node)->href;
6284 if (string == NULL)
6285 return(0);
6286 if (string[0] == 0)
6287 return(0);
6288 return(((unsigned int) string[0]) +
6289 (((unsigned int) string[1]) << 8));
6290 case XML_ATTRIBUTE_NODE:
6291 tmp = ((xmlAttrPtr) node)->children;
6292 break;
6293 case XML_ELEMENT_NODE:
6294 tmp = node->children;
6295 break;
6296 default:
6297 return(0);
6298 }
6299 while (tmp != NULL) {
6300 switch (tmp->type) {
6301 case XML_COMMENT_NODE:
6302 case XML_PI_NODE:
6303 case XML_CDATA_SECTION_NODE:
6304 case XML_TEXT_NODE:
6305 string = tmp->content;
6306 break;
6307 case XML_NAMESPACE_DECL:
6308 string = ((xmlNsPtr)tmp)->href;
6309 break;
6310 default:
6311 break;
6312 }
6313 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006314 if (len == 1) {
6315 return(ret + (((unsigned int) string[0]) << 8));
6316 }
6317 if (string[1] == 0) {
6318 len = 1;
6319 ret = (unsigned int) string[0];
6320 } else {
6321 return(((unsigned int) string[0]) +
6322 (((unsigned int) string[1]) << 8));
6323 }
6324 }
6325 /*
6326 * Skip to next node
6327 */
6328 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6329 if (tmp->children->type != XML_ENTITY_DECL) {
6330 tmp = tmp->children;
6331 continue;
6332 }
6333 }
6334 if (tmp == node)
6335 break;
6336
6337 if (tmp->next != NULL) {
6338 tmp = tmp->next;
6339 continue;
6340 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00006341
Daniel Veillardf06307e2001-07-03 10:35:50 +00006342 do {
6343 tmp = tmp->parent;
6344 if (tmp == NULL)
6345 break;
6346 if (tmp == node) {
6347 tmp = NULL;
6348 break;
6349 }
6350 if (tmp->next != NULL) {
6351 tmp = tmp->next;
6352 break;
6353 }
6354 } while (tmp != NULL);
6355 }
6356 return(ret);
6357}
6358
6359/**
6360 * xmlXPathStringHash:
6361 * @string: a string
6362 *
6363 * Function computing the beginning of the string value of the node,
6364 * used to speed up comparisons
6365 *
6366 * Returns an int usable as a hash
6367 */
6368static unsigned int
6369xmlXPathStringHash(const xmlChar * string) {
6370 if (string == NULL)
6371 return((unsigned int) 0);
6372 if (string[0] == 0)
6373 return(0);
6374 return(((unsigned int) string[0]) +
6375 (((unsigned int) string[1]) << 8));
6376}
6377
6378/**
Owen Taylor3473f882001-02-23 17:55:21 +00006379 * xmlXPathCompareNodeSetFloat:
6380 * @ctxt: the XPath Parser context
6381 * @inf: less than (1) or greater than (0)
6382 * @strict: is the comparison strict
6383 * @arg: the node set
6384 * @f: the value
6385 *
6386 * Implement the compare operation between a nodeset and a number
6387 * @ns < @val (1, 1, ...
6388 * @ns <= @val (1, 0, ...
6389 * @ns > @val (0, 1, ...
6390 * @ns >= @val (0, 0, ...
6391 *
6392 * If one object to be compared is a node-set and the other is a number,
6393 * then the comparison will be true if and only if there is a node in the
6394 * node-set such that the result of performing the comparison on the number
6395 * to be compared and on the result of converting the string-value of that
6396 * node to a number using the number function is true.
6397 *
6398 * Returns 0 or 1 depending on the results of the test.
6399 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006400static int
Owen Taylor3473f882001-02-23 17:55:21 +00006401xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6402 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6403 int i, ret = 0;
6404 xmlNodeSetPtr ns;
6405 xmlChar *str2;
6406
6407 if ((f == NULL) || (arg == NULL) ||
6408 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006409 xmlXPathReleaseObject(ctxt->context, arg);
6410 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006411 return(0);
6412 }
6413 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006414 if (ns != NULL) {
6415 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006416 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006417 if (str2 != NULL) {
6418 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006419 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006420 xmlFree(str2);
6421 xmlXPathNumberFunction(ctxt, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006422 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006423 ret = xmlXPathCompareValues(ctxt, inf, strict);
6424 if (ret)
6425 break;
6426 }
6427 }
Owen Taylor3473f882001-02-23 17:55:21 +00006428 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006429 xmlXPathReleaseObject(ctxt->context, arg);
6430 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006431 return(ret);
6432}
6433
6434/**
6435 * xmlXPathCompareNodeSetString:
6436 * @ctxt: the XPath Parser context
6437 * @inf: less than (1) or greater than (0)
6438 * @strict: is the comparison strict
6439 * @arg: the node set
6440 * @s: the value
6441 *
6442 * Implement the compare operation between a nodeset and a string
6443 * @ns < @val (1, 1, ...
6444 * @ns <= @val (1, 0, ...
6445 * @ns > @val (0, 1, ...
6446 * @ns >= @val (0, 0, ...
6447 *
6448 * If one object to be compared is a node-set and the other is a string,
6449 * then the comparison will be true if and only if there is a node in
6450 * the node-set such that the result of performing the comparison on the
6451 * string-value of the node and the other string is true.
6452 *
6453 * Returns 0 or 1 depending on the results of the test.
6454 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006455static int
Owen Taylor3473f882001-02-23 17:55:21 +00006456xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6457 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6458 int i, ret = 0;
6459 xmlNodeSetPtr ns;
6460 xmlChar *str2;
6461
6462 if ((s == NULL) || (arg == NULL) ||
6463 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006464 xmlXPathReleaseObject(ctxt->context, arg);
6465 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006466 return(0);
6467 }
6468 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006469 if (ns != NULL) {
6470 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006471 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006472 if (str2 != NULL) {
6473 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006474 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006475 xmlFree(str2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006476 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006477 ret = xmlXPathCompareValues(ctxt, inf, strict);
6478 if (ret)
6479 break;
6480 }
6481 }
Owen Taylor3473f882001-02-23 17:55:21 +00006482 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006483 xmlXPathReleaseObject(ctxt->context, arg);
6484 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006485 return(ret);
6486}
6487
6488/**
6489 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006490 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00006491 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006492 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00006493 * @arg2: the second node set object
6494 *
6495 * Implement the compare operation on nodesets:
6496 *
6497 * If both objects to be compared are node-sets, then the comparison
6498 * will be true if and only if there is a node in the first node-set
6499 * and a node in the second node-set such that the result of performing
Daniel Veillard45490ae2008-07-29 09:13:19 +00006500 * the comparison on the string-values of the two nodes is true.
Owen Taylor3473f882001-02-23 17:55:21 +00006501 * ....
6502 * When neither object to be compared is a node-set and the operator
6503 * is <=, <, >= or >, then the objects are compared by converting both
6504 * objects to numbers and comparing the numbers according to IEEE 754.
6505 * ....
6506 * The number function converts its argument to a number as follows:
6507 * - a string that consists of optional whitespace followed by an
6508 * optional minus sign followed by a Number followed by whitespace
6509 * is converted to the IEEE 754 number that is nearest (according
6510 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6511 * represented by the string; any other string is converted to NaN
6512 *
6513 * Conclusion all nodes need to be converted first to their string value
Daniel Veillard45490ae2008-07-29 09:13:19 +00006514 * and then the comparison must be done when possible
Owen Taylor3473f882001-02-23 17:55:21 +00006515 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006516static int
6517xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00006518 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6519 int i, j, init = 0;
6520 double val1;
6521 double *values2;
6522 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006523 xmlNodeSetPtr ns1;
6524 xmlNodeSetPtr ns2;
6525
6526 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006527 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6528 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006529 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006530 }
Owen Taylor3473f882001-02-23 17:55:21 +00006531 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006532 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6533 xmlXPathFreeObject(arg1);
6534 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006535 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006536 }
Owen Taylor3473f882001-02-23 17:55:21 +00006537
6538 ns1 = arg1->nodesetval;
6539 ns2 = arg2->nodesetval;
6540
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006541 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006542 xmlXPathFreeObject(arg1);
6543 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006544 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006545 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006546 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006547 xmlXPathFreeObject(arg1);
6548 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006549 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006550 }
Owen Taylor3473f882001-02-23 17:55:21 +00006551
6552 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6553 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006554 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00006555 xmlXPathFreeObject(arg1);
6556 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006557 return(0);
6558 }
6559 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006560 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00006561 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00006562 continue;
6563 for (j = 0;j < ns2->nodeNr;j++) {
6564 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006565 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00006566 }
Daniel Veillardcda96922001-08-21 10:56:31 +00006567 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00006568 continue;
Daniel Veillard45490ae2008-07-29 09:13:19 +00006569 if (inf && strict)
Owen Taylor3473f882001-02-23 17:55:21 +00006570 ret = (val1 < values2[j]);
6571 else if (inf && !strict)
6572 ret = (val1 <= values2[j]);
6573 else if (!inf && strict)
6574 ret = (val1 > values2[j]);
6575 else if (!inf && !strict)
6576 ret = (val1 >= values2[j]);
6577 if (ret)
6578 break;
6579 }
6580 if (ret)
6581 break;
6582 init = 1;
6583 }
6584 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006585 xmlXPathFreeObject(arg1);
6586 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006587 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006588}
6589
6590/**
6591 * xmlXPathCompareNodeSetValue:
6592 * @ctxt: the XPath Parser context
6593 * @inf: less than (1) or greater than (0)
6594 * @strict: is the comparison strict
6595 * @arg: the node set
6596 * @val: the value
6597 *
6598 * Implement the compare operation between a nodeset and a value
6599 * @ns < @val (1, 1, ...
6600 * @ns <= @val (1, 0, ...
6601 * @ns > @val (0, 1, ...
6602 * @ns >= @val (0, 0, ...
6603 *
6604 * If one object to be compared is a node-set and the other is a boolean,
6605 * then the comparison will be true if and only if the result of performing
6606 * the comparison on the boolean and on the result of converting
6607 * the node-set to a boolean using the boolean function is true.
6608 *
6609 * Returns 0 or 1 depending on the results of the test.
6610 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006611static int
Owen Taylor3473f882001-02-23 17:55:21 +00006612xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6613 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6614 if ((val == NULL) || (arg == NULL) ||
6615 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6616 return(0);
6617
6618 switch(val->type) {
6619 case XPATH_NUMBER:
6620 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6621 case XPATH_NODESET:
6622 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006623 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00006624 case XPATH_STRING:
6625 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6626 case XPATH_BOOLEAN:
6627 valuePush(ctxt, arg);
6628 xmlXPathBooleanFunction(ctxt, 1);
6629 valuePush(ctxt, val);
6630 return(xmlXPathCompareValues(ctxt, inf, strict));
6631 default:
6632 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00006633 }
6634 return(0);
6635}
6636
6637/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006638 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00006639 * @arg: the nodeset object argument
6640 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00006641 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006642 *
6643 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6644 * If one object to be compared is a node-set and the other is a string,
6645 * then the comparison will be true if and only if there is a node in
6646 * the node-set such that the result of performing the comparison on the
6647 * string-value of the node and the other string is true.
6648 *
6649 * Returns 0 or 1 depending on the results of the test.
6650 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006651static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006652xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006653{
Owen Taylor3473f882001-02-23 17:55:21 +00006654 int i;
6655 xmlNodeSetPtr ns;
6656 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006657 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00006658
6659 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00006660 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6661 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006662 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00006663 /*
6664 * A NULL nodeset compared with a string is always false
6665 * (since there is no node equal, and no node not equal)
6666 */
6667 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00006668 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00006669 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006670 for (i = 0; i < ns->nodeNr; i++) {
6671 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6672 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6673 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6674 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006675 if (neq)
6676 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006677 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00006678 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6679 if (neq)
6680 continue;
6681 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006682 } else if (neq) {
6683 if (str2 != NULL)
6684 xmlFree(str2);
6685 return (1);
6686 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006687 if (str2 != NULL)
6688 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006689 } else if (neq)
6690 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00006691 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006692 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006693}
6694
6695/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006696 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00006697 * @arg: the nodeset object argument
6698 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00006699 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006700 *
6701 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6702 * If one object to be compared is a node-set and the other is a number,
6703 * then the comparison will be true if and only if there is a node in
6704 * the node-set such that the result of performing the comparison on the
6705 * number to be compared and on the result of converting the string-value
6706 * of that node to a number using the number function is true.
6707 *
6708 * Returns 0 or 1 depending on the results of the test.
6709 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006710static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006711xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6712 xmlXPathObjectPtr arg, double f, int neq) {
6713 int i, ret=0;
6714 xmlNodeSetPtr ns;
6715 xmlChar *str2;
6716 xmlXPathObjectPtr val;
6717 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00006718
6719 if ((arg == NULL) ||
6720 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6721 return(0);
6722
William M. Brack0c022ad2002-07-12 00:56:01 +00006723 ns = arg->nodesetval;
6724 if (ns != NULL) {
6725 for (i=0;i<ns->nodeNr;i++) {
6726 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6727 if (str2 != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006728 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
William M. Brack0c022ad2002-07-12 00:56:01 +00006729 xmlFree(str2);
6730 xmlXPathNumberFunction(ctxt, 1);
6731 val = valuePop(ctxt);
6732 v = val->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006733 xmlXPathReleaseObject(ctxt->context, val);
William M. Brack0c022ad2002-07-12 00:56:01 +00006734 if (!xmlXPathIsNaN(v)) {
6735 if ((!neq) && (v==f)) {
6736 ret = 1;
6737 break;
6738 } else if ((neq) && (v!=f)) {
6739 ret = 1;
6740 break;
6741 }
William M. Brack32f0f712005-07-14 07:00:33 +00006742 } else { /* NaN is unequal to any value */
6743 if (neq)
6744 ret = 1;
William M. Brack0c022ad2002-07-12 00:56:01 +00006745 }
6746 }
6747 }
6748 }
6749
6750 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006751}
6752
6753
6754/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006755 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00006756 * @arg1: first nodeset object argument
6757 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00006758 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006759 *
William M. Brack0c022ad2002-07-12 00:56:01 +00006760 * Implement the equal / not equal operation on XPath nodesets:
6761 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00006762 * If both objects to be compared are node-sets, then the comparison
6763 * will be true if and only if there is a node in the first node-set and
6764 * a node in the second node-set such that the result of performing the
6765 * comparison on the string-values of the two nodes is true.
6766 *
6767 * (needless to say, this is a costly operation)
6768 *
6769 * Returns 0 or 1 depending on the results of the test.
6770 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006771static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006772xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00006773 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006774 unsigned int *hashs1;
6775 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00006776 xmlChar **values1;
6777 xmlChar **values2;
6778 int ret = 0;
6779 xmlNodeSetPtr ns1;
6780 xmlNodeSetPtr ns2;
6781
6782 if ((arg1 == NULL) ||
6783 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6784 return(0);
6785 if ((arg2 == NULL) ||
6786 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6787 return(0);
6788
6789 ns1 = arg1->nodesetval;
6790 ns2 = arg2->nodesetval;
6791
Daniel Veillard911f49a2001-04-07 15:39:35 +00006792 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006793 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006794 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006795 return(0);
6796
6797 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00006798 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00006799 */
William M. Brack0c022ad2002-07-12 00:56:01 +00006800 if (neq == 0)
6801 for (i = 0;i < ns1->nodeNr;i++)
6802 for (j = 0;j < ns2->nodeNr;j++)
6803 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6804 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006805
6806 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006807 if (values1 == NULL) {
6808 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006809 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006810 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006811 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6812 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006813 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006814 xmlFree(values1);
6815 return(0);
6816 }
Owen Taylor3473f882001-02-23 17:55:21 +00006817 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6818 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6819 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006820 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006821 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00006822 xmlFree(values1);
6823 return(0);
6824 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006825 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6826 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006827 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006828 xmlFree(hashs1);
6829 xmlFree(values1);
6830 xmlFree(values2);
6831 return(0);
6832 }
Owen Taylor3473f882001-02-23 17:55:21 +00006833 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6834 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006835 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006836 for (j = 0;j < ns2->nodeNr;j++) {
6837 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006838 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006839 if (hashs1[i] != hashs2[j]) {
6840 if (neq) {
6841 ret = 1;
6842 break;
6843 }
6844 }
6845 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006846 if (values1[i] == NULL)
6847 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6848 if (values2[j] == NULL)
6849 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006850 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006851 if (ret)
6852 break;
6853 }
Owen Taylor3473f882001-02-23 17:55:21 +00006854 }
6855 if (ret)
6856 break;
6857 }
6858 for (i = 0;i < ns1->nodeNr;i++)
6859 if (values1[i] != NULL)
6860 xmlFree(values1[i]);
6861 for (j = 0;j < ns2->nodeNr;j++)
6862 if (values2[j] != NULL)
6863 xmlFree(values2[j]);
6864 xmlFree(values1);
6865 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006866 xmlFree(hashs1);
6867 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00006868 return(ret);
6869}
6870
William M. Brack0c022ad2002-07-12 00:56:01 +00006871static int
6872xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6873 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00006874 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00006875 /*
6876 *At this point we are assured neither arg1 nor arg2
6877 *is a nodeset, so we can just pick the appropriate routine.
6878 */
Owen Taylor3473f882001-02-23 17:55:21 +00006879 switch (arg1->type) {
6880 case XPATH_UNDEFINED:
6881#ifdef DEBUG_EXPR
6882 xmlGenericError(xmlGenericErrorContext,
6883 "Equal: undefined\n");
6884#endif
6885 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006886 case XPATH_BOOLEAN:
6887 switch (arg2->type) {
6888 case XPATH_UNDEFINED:
6889#ifdef DEBUG_EXPR
6890 xmlGenericError(xmlGenericErrorContext,
6891 "Equal: undefined\n");
6892#endif
6893 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006894 case XPATH_BOOLEAN:
6895#ifdef DEBUG_EXPR
6896 xmlGenericError(xmlGenericErrorContext,
6897 "Equal: %d boolean %d \n",
6898 arg1->boolval, arg2->boolval);
6899#endif
6900 ret = (arg1->boolval == arg2->boolval);
6901 break;
6902 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00006903 ret = (arg1->boolval ==
6904 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006905 break;
6906 case XPATH_STRING:
6907 if ((arg2->stringval == NULL) ||
6908 (arg2->stringval[0] == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00006909 else
Owen Taylor3473f882001-02-23 17:55:21 +00006910 ret = 1;
6911 ret = (arg1->boolval == ret);
6912 break;
6913 case XPATH_USERS:
6914 case XPATH_POINT:
6915 case XPATH_RANGE:
6916 case XPATH_LOCATIONSET:
6917 TODO
6918 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006919 case XPATH_NODESET:
6920 case XPATH_XSLT_TREE:
6921 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006922 }
6923 break;
6924 case XPATH_NUMBER:
6925 switch (arg2->type) {
6926 case XPATH_UNDEFINED:
6927#ifdef DEBUG_EXPR
6928 xmlGenericError(xmlGenericErrorContext,
6929 "Equal: undefined\n");
6930#endif
6931 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006932 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00006933 ret = (arg2->boolval==
6934 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006935 break;
6936 case XPATH_STRING:
6937 valuePush(ctxt, arg2);
6938 xmlXPathNumberFunction(ctxt, 1);
6939 arg2 = valuePop(ctxt);
6940 /* no break on purpose */
6941 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006942 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00006943 if (xmlXPathIsNaN(arg1->floatval) ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00006944 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00006945 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006946 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6947 if (xmlXPathIsInf(arg2->floatval) == 1)
6948 ret = 1;
6949 else
6950 ret = 0;
6951 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6952 if (xmlXPathIsInf(arg2->floatval) == -1)
6953 ret = 1;
6954 else
6955 ret = 0;
6956 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6957 if (xmlXPathIsInf(arg1->floatval) == 1)
6958 ret = 1;
6959 else
6960 ret = 0;
6961 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6962 if (xmlXPathIsInf(arg1->floatval) == -1)
6963 ret = 1;
6964 else
6965 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00006966 } else {
6967 ret = (arg1->floatval == arg2->floatval);
6968 }
Owen Taylor3473f882001-02-23 17:55:21 +00006969 break;
6970 case XPATH_USERS:
6971 case XPATH_POINT:
6972 case XPATH_RANGE:
6973 case XPATH_LOCATIONSET:
6974 TODO
6975 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006976 case XPATH_NODESET:
6977 case XPATH_XSLT_TREE:
6978 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006979 }
6980 break;
6981 case XPATH_STRING:
6982 switch (arg2->type) {
6983 case XPATH_UNDEFINED:
6984#ifdef DEBUG_EXPR
6985 xmlGenericError(xmlGenericErrorContext,
6986 "Equal: undefined\n");
6987#endif
6988 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006989 case XPATH_BOOLEAN:
6990 if ((arg1->stringval == NULL) ||
6991 (arg1->stringval[0] == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00006992 else
Owen Taylor3473f882001-02-23 17:55:21 +00006993 ret = 1;
6994 ret = (arg2->boolval == ret);
6995 break;
6996 case XPATH_STRING:
6997 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6998 break;
6999 case XPATH_NUMBER:
7000 valuePush(ctxt, arg1);
7001 xmlXPathNumberFunction(ctxt, 1);
7002 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007003 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00007004 if (xmlXPathIsNaN(arg1->floatval) ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00007005 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00007006 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007007 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7008 if (xmlXPathIsInf(arg2->floatval) == 1)
7009 ret = 1;
7010 else
7011 ret = 0;
7012 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7013 if (xmlXPathIsInf(arg2->floatval) == -1)
7014 ret = 1;
7015 else
7016 ret = 0;
7017 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7018 if (xmlXPathIsInf(arg1->floatval) == 1)
7019 ret = 1;
7020 else
7021 ret = 0;
7022 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7023 if (xmlXPathIsInf(arg1->floatval) == -1)
7024 ret = 1;
7025 else
7026 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007027 } else {
7028 ret = (arg1->floatval == arg2->floatval);
7029 }
Owen Taylor3473f882001-02-23 17:55:21 +00007030 break;
7031 case XPATH_USERS:
7032 case XPATH_POINT:
7033 case XPATH_RANGE:
7034 case XPATH_LOCATIONSET:
7035 TODO
7036 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007037 case XPATH_NODESET:
7038 case XPATH_XSLT_TREE:
7039 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007040 }
7041 break;
7042 case XPATH_USERS:
7043 case XPATH_POINT:
7044 case XPATH_RANGE:
7045 case XPATH_LOCATIONSET:
7046 TODO
7047 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00007048 case XPATH_NODESET:
7049 case XPATH_XSLT_TREE:
7050 break;
Owen Taylor3473f882001-02-23 17:55:21 +00007051 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007052 xmlXPathReleaseObject(ctxt->context, arg1);
7053 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007054 return(ret);
7055}
7056
William M. Brack0c022ad2002-07-12 00:56:01 +00007057/**
7058 * xmlXPathEqualValues:
7059 * @ctxt: the XPath Parser context
7060 *
7061 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7062 *
7063 * Returns 0 or 1 depending on the results of the test.
7064 */
7065int
7066xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7067 xmlXPathObjectPtr arg1, arg2, argtmp;
7068 int ret = 0;
7069
Daniel Veillard6128c012004-11-08 17:16:15 +00007070 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007071 arg2 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007072 arg1 = valuePop(ctxt);
7073 if ((arg1 == NULL) || (arg2 == NULL)) {
7074 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007075 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007076 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007077 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007078 XP_ERROR0(XPATH_INVALID_OPERAND);
7079 }
7080
7081 if (arg1 == arg2) {
7082#ifdef DEBUG_EXPR
7083 xmlGenericError(xmlGenericErrorContext,
7084 "Equal: by pointer\n");
7085#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00007086 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007087 return(1);
7088 }
7089
7090 /*
7091 *If either argument is a nodeset, it's a 'special case'
7092 */
7093 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7094 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7095 /*
7096 *Hack it to assure arg1 is the nodeset
7097 */
7098 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7099 argtmp = arg2;
7100 arg2 = arg1;
7101 arg1 = argtmp;
7102 }
7103 switch (arg2->type) {
7104 case XPATH_UNDEFINED:
7105#ifdef DEBUG_EXPR
7106 xmlGenericError(xmlGenericErrorContext,
7107 "Equal: undefined\n");
7108#endif
7109 break;
7110 case XPATH_NODESET:
7111 case XPATH_XSLT_TREE:
7112 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7113 break;
7114 case XPATH_BOOLEAN:
7115 if ((arg1->nodesetval == NULL) ||
7116 (arg1->nodesetval->nodeNr == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007117 else
William M. Brack0c022ad2002-07-12 00:56:01 +00007118 ret = 1;
7119 ret = (ret == arg2->boolval);
7120 break;
7121 case XPATH_NUMBER:
7122 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7123 break;
7124 case XPATH_STRING:
7125 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7126 break;
7127 case XPATH_USERS:
7128 case XPATH_POINT:
7129 case XPATH_RANGE:
7130 case XPATH_LOCATIONSET:
7131 TODO
7132 break;
7133 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007134 xmlXPathReleaseObject(ctxt->context, arg1);
7135 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007136 return(ret);
7137 }
7138
7139 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7140}
7141
7142/**
7143 * xmlXPathNotEqualValues:
7144 * @ctxt: the XPath Parser context
7145 *
7146 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7147 *
7148 * Returns 0 or 1 depending on the results of the test.
7149 */
7150int
7151xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7152 xmlXPathObjectPtr arg1, arg2, argtmp;
7153 int ret = 0;
7154
Daniel Veillard6128c012004-11-08 17:16:15 +00007155 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007156 arg2 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007157 arg1 = valuePop(ctxt);
7158 if ((arg1 == NULL) || (arg2 == NULL)) {
7159 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007160 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007161 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007162 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007163 XP_ERROR0(XPATH_INVALID_OPERAND);
7164 }
7165
7166 if (arg1 == arg2) {
7167#ifdef DEBUG_EXPR
7168 xmlGenericError(xmlGenericErrorContext,
7169 "NotEqual: by pointer\n");
7170#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007171 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007172 return(0);
7173 }
7174
7175 /*
7176 *If either argument is a nodeset, it's a 'special case'
7177 */
7178 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7179 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7180 /*
7181 *Hack it to assure arg1 is the nodeset
7182 */
7183 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7184 argtmp = arg2;
7185 arg2 = arg1;
7186 arg1 = argtmp;
7187 }
7188 switch (arg2->type) {
7189 case XPATH_UNDEFINED:
7190#ifdef DEBUG_EXPR
7191 xmlGenericError(xmlGenericErrorContext,
7192 "NotEqual: undefined\n");
7193#endif
7194 break;
7195 case XPATH_NODESET:
7196 case XPATH_XSLT_TREE:
7197 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7198 break;
7199 case XPATH_BOOLEAN:
7200 if ((arg1->nodesetval == NULL) ||
7201 (arg1->nodesetval->nodeNr == 0)) ret = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007202 else
William M. Brack0c022ad2002-07-12 00:56:01 +00007203 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00007204 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00007205 break;
7206 case XPATH_NUMBER:
7207 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7208 break;
7209 case XPATH_STRING:
7210 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7211 break;
7212 case XPATH_USERS:
7213 case XPATH_POINT:
7214 case XPATH_RANGE:
7215 case XPATH_LOCATIONSET:
7216 TODO
7217 break;
7218 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007219 xmlXPathReleaseObject(ctxt->context, arg1);
7220 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007221 return(ret);
7222 }
7223
7224 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7225}
Owen Taylor3473f882001-02-23 17:55:21 +00007226
7227/**
7228 * xmlXPathCompareValues:
7229 * @ctxt: the XPath Parser context
7230 * @inf: less than (1) or greater than (0)
7231 * @strict: is the comparison strict
7232 *
Daniel Veillard45490ae2008-07-29 09:13:19 +00007233 * Implement the compare operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007234 * @arg1 < @arg2 (1, 1, ...
7235 * @arg1 <= @arg2 (1, 0, ...
7236 * @arg1 > @arg2 (0, 1, ...
7237 * @arg1 >= @arg2 (0, 0, ...
7238 *
7239 * When neither object to be compared is a node-set and the operator is
7240 * <=, <, >=, >, then the objects are compared by converted both objects
7241 * to numbers and comparing the numbers according to IEEE 754. The <
7242 * comparison will be true if and only if the first number is less than the
7243 * second number. The <= comparison will be true if and only if the first
7244 * number is less than or equal to the second number. The > comparison
7245 * will be true if and only if the first number is greater than the second
7246 * number. The >= comparison will be true if and only if the first number
7247 * is greater than or equal to the second number.
7248 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007249 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00007250 */
7251int
7252xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007253 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007254 xmlXPathObjectPtr arg1, arg2;
7255
Daniel Veillard6128c012004-11-08 17:16:15 +00007256 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007257 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007258 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007259 if ((arg1 == NULL) || (arg2 == NULL)) {
7260 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007261 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007262 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007263 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007264 XP_ERROR0(XPATH_INVALID_OPERAND);
7265 }
7266
William M. Brack0c022ad2002-07-12 00:56:01 +00007267 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7268 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
William M. Brackd6e347e2005-04-15 01:34:41 +00007269 /*
7270 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7271 * are not freed from within this routine; they will be freed from the
7272 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7273 */
William M. Brack0c022ad2002-07-12 00:56:01 +00007274 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7275 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007276 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007277 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00007278 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007279 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7280 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007281 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007282 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7283 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00007284 }
7285 }
7286 return(ret);
7287 }
7288
7289 if (arg1->type != XPATH_NUMBER) {
7290 valuePush(ctxt, arg1);
7291 xmlXPathNumberFunction(ctxt, 1);
7292 arg1 = valuePop(ctxt);
7293 }
7294 if (arg1->type != XPATH_NUMBER) {
7295 xmlXPathFreeObject(arg1);
7296 xmlXPathFreeObject(arg2);
7297 XP_ERROR0(XPATH_INVALID_OPERAND);
7298 }
7299 if (arg2->type != XPATH_NUMBER) {
7300 valuePush(ctxt, arg2);
7301 xmlXPathNumberFunction(ctxt, 1);
7302 arg2 = valuePop(ctxt);
7303 }
7304 if (arg2->type != XPATH_NUMBER) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007305 xmlXPathReleaseObject(ctxt->context, arg1);
7306 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007307 XP_ERROR0(XPATH_INVALID_OPERAND);
7308 }
7309 /*
7310 * Add tests for infinity and nan
7311 * => feedback on 3.4 for Inf and NaN
7312 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007313 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00007314 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007315 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007316 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007317 arg1i=xmlXPathIsInf(arg1->floatval);
7318 arg2i=xmlXPathIsInf(arg2->floatval);
7319 if (inf && strict) {
7320 if ((arg1i == -1 && arg2i != -1) ||
7321 (arg2i == 1 && arg1i != 1)) {
7322 ret = 1;
7323 } else if (arg1i == 0 && arg2i == 0) {
7324 ret = (arg1->floatval < arg2->floatval);
7325 } else {
7326 ret = 0;
7327 }
7328 }
7329 else if (inf && !strict) {
7330 if (arg1i == -1 || arg2i == 1) {
7331 ret = 1;
7332 } else if (arg1i == 0 && arg2i == 0) {
7333 ret = (arg1->floatval <= arg2->floatval);
7334 } else {
7335 ret = 0;
7336 }
7337 }
7338 else if (!inf && strict) {
7339 if ((arg1i == 1 && arg2i != 1) ||
7340 (arg2i == -1 && arg1i != -1)) {
7341 ret = 1;
7342 } else if (arg1i == 0 && arg2i == 0) {
7343 ret = (arg1->floatval > arg2->floatval);
7344 } else {
7345 ret = 0;
7346 }
7347 }
7348 else if (!inf && !strict) {
7349 if (arg1i == 1 || arg2i == -1) {
7350 ret = 1;
7351 } else if (arg1i == 0 && arg2i == 0) {
7352 ret = (arg1->floatval >= arg2->floatval);
7353 } else {
7354 ret = 0;
7355 }
7356 }
Daniel Veillard21458c82002-03-27 16:12:22 +00007357 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007358 xmlXPathReleaseObject(ctxt->context, arg1);
7359 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007360 return(ret);
7361}
7362
7363/**
7364 * xmlXPathValueFlipSign:
7365 * @ctxt: the XPath Parser context
7366 *
7367 * Implement the unary - operation on an XPath object
7368 * The numeric operators convert their operands to numbers as if
7369 * by calling the number function.
7370 */
7371void
7372xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007373 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007374 CAST_TO_NUMBER;
7375 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007376 if (xmlXPathIsNaN(ctxt->value->floatval))
7377 ctxt->value->floatval=xmlXPathNAN;
7378 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7379 ctxt->value->floatval=xmlXPathNINF;
7380 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7381 ctxt->value->floatval=xmlXPathPINF;
7382 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007383 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7384 ctxt->value->floatval = xmlXPathNZERO;
7385 else
7386 ctxt->value->floatval = 0;
7387 }
7388 else
7389 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00007390}
7391
7392/**
7393 * xmlXPathAddValues:
7394 * @ctxt: the XPath Parser context
7395 *
7396 * Implement the add operation on XPath objects:
7397 * The numeric operators convert their operands to numbers as if
7398 * by calling the number function.
7399 */
7400void
7401xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7402 xmlXPathObjectPtr arg;
7403 double val;
7404
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007405 arg = valuePop(ctxt);
7406 if (arg == NULL)
7407 XP_ERROR(XPATH_INVALID_OPERAND);
7408 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007409 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007410 CAST_TO_NUMBER;
7411 CHECK_TYPE(XPATH_NUMBER);
7412 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00007413}
7414
7415/**
7416 * xmlXPathSubValues:
7417 * @ctxt: the XPath Parser context
7418 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007419 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007420 * The numeric operators convert their operands to numbers as if
7421 * by calling the number function.
7422 */
7423void
7424xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7425 xmlXPathObjectPtr arg;
7426 double val;
7427
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007428 arg = valuePop(ctxt);
7429 if (arg == NULL)
7430 XP_ERROR(XPATH_INVALID_OPERAND);
7431 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007432 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007433 CAST_TO_NUMBER;
7434 CHECK_TYPE(XPATH_NUMBER);
7435 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007436}
7437
7438/**
7439 * xmlXPathMultValues:
7440 * @ctxt: the XPath Parser context
7441 *
7442 * Implement the multiply operation on XPath objects:
7443 * The numeric operators convert their operands to numbers as if
7444 * by calling the number function.
7445 */
7446void
7447xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7448 xmlXPathObjectPtr arg;
7449 double val;
7450
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007451 arg = valuePop(ctxt);
7452 if (arg == NULL)
7453 XP_ERROR(XPATH_INVALID_OPERAND);
7454 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007455 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007456 CAST_TO_NUMBER;
7457 CHECK_TYPE(XPATH_NUMBER);
7458 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007459}
7460
7461/**
7462 * xmlXPathDivValues:
7463 * @ctxt: the XPath Parser context
7464 *
7465 * Implement the div operation on XPath objects @arg1 / @arg2:
7466 * The numeric operators convert their operands to numbers as if
7467 * by calling the number function.
7468 */
7469void
7470xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7471 xmlXPathObjectPtr arg;
7472 double val;
7473
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007474 arg = valuePop(ctxt);
7475 if (arg == NULL)
7476 XP_ERROR(XPATH_INVALID_OPERAND);
7477 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007478 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007479 CAST_TO_NUMBER;
7480 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007481 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7482 ctxt->value->floatval = xmlXPathNAN;
7483 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007484 if (ctxt->value->floatval == 0)
7485 ctxt->value->floatval = xmlXPathNAN;
7486 else if (ctxt->value->floatval > 0)
7487 ctxt->value->floatval = xmlXPathNINF;
7488 else if (ctxt->value->floatval < 0)
7489 ctxt->value->floatval = xmlXPathPINF;
7490 }
7491 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007492 if (ctxt->value->floatval == 0)
7493 ctxt->value->floatval = xmlXPathNAN;
7494 else if (ctxt->value->floatval > 0)
7495 ctxt->value->floatval = xmlXPathPINF;
7496 else if (ctxt->value->floatval < 0)
7497 ctxt->value->floatval = xmlXPathNINF;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007498 } else
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007499 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007500}
7501
7502/**
7503 * xmlXPathModValues:
7504 * @ctxt: the XPath Parser context
7505 *
7506 * Implement the mod operation on XPath objects: @arg1 / @arg2
7507 * The numeric operators convert their operands to numbers as if
7508 * by calling the number function.
7509 */
7510void
7511xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7512 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00007513 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00007514
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007515 arg = valuePop(ctxt);
7516 if (arg == NULL)
7517 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007518 arg2 = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007519 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007520 CAST_TO_NUMBER;
7521 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007522 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00007523 if (arg2 == 0)
7524 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007525 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00007526 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007527 }
Owen Taylor3473f882001-02-23 17:55:21 +00007528}
7529
7530/************************************************************************
7531 * *
7532 * The traversal functions *
7533 * *
7534 ************************************************************************/
7535
Owen Taylor3473f882001-02-23 17:55:21 +00007536/*
7537 * A traversal function enumerates nodes along an axis.
7538 * Initially it must be called with NULL, and it indicates
7539 * termination on the axis by returning NULL.
7540 */
7541typedef xmlNodePtr (*xmlXPathTraversalFunction)
7542 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7543
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007544/*
7545 * xmlXPathTraversalFunctionExt:
7546 * A traversal function enumerates nodes along an axis.
7547 * Initially it must be called with NULL, and it indicates
7548 * termination on the axis by returning NULL.
7549 * The context node of the traversal is specified via @contextNode.
7550 */
7551typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7552 (xmlNodePtr cur, xmlNodePtr contextNode);
7553
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00007554/*
7555 * xmlXPathNodeSetMergeFunction:
7556 * Used for merging node sets in xmlXPathCollectAndTest().
7557 */
7558typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7559 (xmlNodeSetPtr, xmlNodeSetPtr, int);
7560
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007561
Owen Taylor3473f882001-02-23 17:55:21 +00007562/**
7563 * xmlXPathNextSelf:
7564 * @ctxt: the XPath Parser context
7565 * @cur: the current node in the traversal
7566 *
7567 * Traversal function for the "self" direction
7568 * The self axis contains just the context node itself
7569 *
7570 * Returns the next element following that axis
7571 */
7572xmlNodePtr
7573xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007574 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007575 if (cur == NULL)
7576 return(ctxt->context->node);
7577 return(NULL);
7578}
7579
7580/**
7581 * xmlXPathNextChild:
7582 * @ctxt: the XPath Parser context
7583 * @cur: the current node in the traversal
7584 *
7585 * Traversal function for the "child" direction
7586 * The child axis contains the children of the context node in document order.
7587 *
7588 * Returns the next element following that axis
7589 */
7590xmlNodePtr
7591xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007592 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007593 if (cur == NULL) {
7594 if (ctxt->context->node == NULL) return(NULL);
7595 switch (ctxt->context->node->type) {
7596 case XML_ELEMENT_NODE:
7597 case XML_TEXT_NODE:
7598 case XML_CDATA_SECTION_NODE:
7599 case XML_ENTITY_REF_NODE:
7600 case XML_ENTITY_NODE:
7601 case XML_PI_NODE:
7602 case XML_COMMENT_NODE:
7603 case XML_NOTATION_NODE:
7604 case XML_DTD_NODE:
7605 return(ctxt->context->node->children);
7606 case XML_DOCUMENT_NODE:
7607 case XML_DOCUMENT_TYPE_NODE:
7608 case XML_DOCUMENT_FRAG_NODE:
7609 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007610#ifdef LIBXML_DOCB_ENABLED
7611 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007612#endif
7613 return(((xmlDocPtr) ctxt->context->node)->children);
7614 case XML_ELEMENT_DECL:
7615 case XML_ATTRIBUTE_DECL:
7616 case XML_ENTITY_DECL:
7617 case XML_ATTRIBUTE_NODE:
7618 case XML_NAMESPACE_DECL:
7619 case XML_XINCLUDE_START:
7620 case XML_XINCLUDE_END:
7621 return(NULL);
7622 }
7623 return(NULL);
7624 }
7625 if ((cur->type == XML_DOCUMENT_NODE) ||
7626 (cur->type == XML_HTML_DOCUMENT_NODE))
7627 return(NULL);
7628 return(cur->next);
7629}
7630
7631/**
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00007632 * xmlXPathNextChildElement:
7633 * @ctxt: the XPath Parser context
7634 * @cur: the current node in the traversal
7635 *
7636 * Traversal function for the "child" direction and nodes of type element.
7637 * The child axis contains the children of the context node in document order.
7638 *
7639 * Returns the next element following that axis
7640 */
7641static xmlNodePtr
7642xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7643 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7644 if (cur == NULL) {
7645 cur = ctxt->context->node;
7646 if (cur == NULL) return(NULL);
7647 /*
7648 * Get the first element child.
7649 */
7650 switch (cur->type) {
7651 case XML_ELEMENT_NODE:
7652 case XML_DOCUMENT_FRAG_NODE:
7653 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7654 case XML_ENTITY_NODE:
7655 cur = cur->children;
7656 if (cur != NULL) {
7657 if (cur->type == XML_ELEMENT_NODE)
7658 return(cur);
7659 do {
7660 cur = cur->next;
7661 } while ((cur != NULL) &&
7662 (cur->type != XML_ELEMENT_NODE));
7663 return(cur);
7664 }
7665 return(NULL);
7666 case XML_DOCUMENT_NODE:
7667 case XML_HTML_DOCUMENT_NODE:
7668#ifdef LIBXML_DOCB_ENABLED
7669 case XML_DOCB_DOCUMENT_NODE:
7670#endif
7671 return(xmlDocGetRootElement((xmlDocPtr) cur));
7672 default:
7673 return(NULL);
7674 }
7675 return(NULL);
7676 }
7677 /*
7678 * Get the next sibling element node.
7679 */
7680 switch (cur->type) {
7681 case XML_ELEMENT_NODE:
7682 case XML_TEXT_NODE:
7683 case XML_ENTITY_REF_NODE:
7684 case XML_ENTITY_NODE:
7685 case XML_CDATA_SECTION_NODE:
7686 case XML_PI_NODE:
7687 case XML_COMMENT_NODE:
7688 case XML_XINCLUDE_END:
7689 break;
7690 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7691 default:
7692 return(NULL);
7693 }
7694 if (cur->next != NULL) {
7695 if (cur->next->type == XML_ELEMENT_NODE)
7696 return(cur->next);
7697 cur = cur->next;
7698 do {
7699 cur = cur->next;
7700 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7701 return(cur);
7702 }
7703 return(NULL);
7704}
7705
7706/**
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007707 * xmlXPathNextDescendantOrSelfElemParent:
7708 * @ctxt: the XPath Parser context
7709 * @cur: the current node in the traversal
7710 *
7711 * Traversal function for the "descendant-or-self" axis.
7712 * Additionally it returns only nodes which can be parents of
7713 * element nodes.
7714 *
7715 *
7716 * Returns the next element following that axis
7717 */
7718static xmlNodePtr
7719xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7720 xmlNodePtr contextNode)
7721{
7722 if (cur == NULL) {
7723 if (contextNode == NULL)
7724 return(NULL);
7725 switch (contextNode->type) {
7726 case XML_ELEMENT_NODE:
7727 case XML_XINCLUDE_START:
7728 case XML_DOCUMENT_FRAG_NODE:
7729 case XML_DOCUMENT_NODE:
7730#ifdef LIBXML_DOCB_ENABLED
7731 case XML_DOCB_DOCUMENT_NODE:
7732#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +00007733 case XML_HTML_DOCUMENT_NODE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007734 return(contextNode);
7735 default:
Daniel Veillard45490ae2008-07-29 09:13:19 +00007736 return(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007737 }
7738 return(NULL);
7739 } else {
7740 xmlNodePtr start = cur;
7741
7742 while (cur != NULL) {
7743 switch (cur->type) {
7744 case XML_ELEMENT_NODE:
7745 /* TODO: OK to have XInclude here? */
7746 case XML_XINCLUDE_START:
Daniel Veillard45490ae2008-07-29 09:13:19 +00007747 case XML_DOCUMENT_FRAG_NODE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007748 if (cur != start)
7749 return(cur);
7750 if (cur->children != NULL) {
7751 cur = cur->children;
7752 continue;
7753 }
7754 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007755 /* Not sure if we need those here. */
7756 case XML_DOCUMENT_NODE:
Daniel Veillard17970a72006-10-26 08:55:47 +00007757#ifdef LIBXML_DOCB_ENABLED
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007758 case XML_DOCB_DOCUMENT_NODE:
7759#endif
7760 case XML_HTML_DOCUMENT_NODE:
7761 if (cur != start)
7762 return(cur);
7763 return(xmlDocGetRootElement((xmlDocPtr) cur));
7764 default:
7765 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007766 }
7767
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007768next_sibling:
7769 if ((cur == NULL) || (cur == contextNode))
Daniel Veillard45490ae2008-07-29 09:13:19 +00007770 return(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007771 if (cur->next != NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00007772 cur = cur->next;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007773 } else {
7774 cur = cur->parent;
7775 goto next_sibling;
7776 }
7777 }
7778 }
7779 return(NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +00007780}
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007781
7782/**
Owen Taylor3473f882001-02-23 17:55:21 +00007783 * xmlXPathNextDescendant:
7784 * @ctxt: the XPath Parser context
7785 * @cur: the current node in the traversal
7786 *
7787 * Traversal function for the "descendant" direction
7788 * the descendant axis contains the descendants of the context node in document
7789 * order; a descendant is a child or a child of a child and so on.
7790 *
7791 * Returns the next element following that axis
7792 */
7793xmlNodePtr
7794xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007795 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007796 if (cur == NULL) {
7797 if (ctxt->context->node == NULL)
7798 return(NULL);
7799 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7800 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7801 return(NULL);
7802
7803 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7804 return(ctxt->context->doc->children);
7805 return(ctxt->context->node->children);
7806 }
7807
Daniel Veillard567e1b42001-08-01 15:53:47 +00007808 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007809 /*
7810 * Do not descend on entities declarations
7811 */
Daniel Veillard45490ae2008-07-29 09:13:19 +00007812 if (cur->children->type != XML_ENTITY_DECL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007813 cur = cur->children;
7814 /*
7815 * Skip DTDs
7816 */
7817 if (cur->type != XML_DTD_NODE)
7818 return(cur);
7819 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00007820 }
7821
7822 if (cur == ctxt->context->node) return(NULL);
7823
Daniel Veillard68e9e742002-11-16 15:35:11 +00007824 while (cur->next != NULL) {
7825 cur = cur->next;
7826 if ((cur->type != XML_ENTITY_DECL) &&
7827 (cur->type != XML_DTD_NODE))
7828 return(cur);
7829 }
Daniel Veillard45490ae2008-07-29 09:13:19 +00007830
Owen Taylor3473f882001-02-23 17:55:21 +00007831 do {
7832 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00007833 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00007834 if (cur == ctxt->context->node) return(NULL);
7835 if (cur->next != NULL) {
7836 cur = cur->next;
7837 return(cur);
7838 }
7839 } while (cur != NULL);
7840 return(cur);
7841}
7842
7843/**
7844 * xmlXPathNextDescendantOrSelf:
7845 * @ctxt: the XPath Parser context
7846 * @cur: the current node in the traversal
7847 *
7848 * Traversal function for the "descendant-or-self" direction
7849 * the descendant-or-self axis contains the context node and the descendants
7850 * of the context node in document order; thus the context node is the first
7851 * node on the axis, and the first child of the context node is the second node
7852 * on the axis
7853 *
7854 * Returns the next element following that axis
7855 */
7856xmlNodePtr
7857xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007858 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007859 if (cur == NULL) {
7860 if (ctxt->context->node == NULL)
7861 return(NULL);
7862 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7863 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7864 return(NULL);
7865 return(ctxt->context->node);
7866 }
7867
7868 return(xmlXPathNextDescendant(ctxt, cur));
7869}
7870
7871/**
7872 * xmlXPathNextParent:
7873 * @ctxt: the XPath Parser context
7874 * @cur: the current node in the traversal
7875 *
7876 * Traversal function for the "parent" direction
7877 * The parent axis contains the parent of the context node, if there is one.
7878 *
7879 * Returns the next element following that axis
7880 */
7881xmlNodePtr
7882xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007883 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007884 /*
7885 * the parent of an attribute or namespace node is the element
7886 * to which the attribute or namespace node is attached
7887 * Namespace handling !!!
7888 */
7889 if (cur == NULL) {
7890 if (ctxt->context->node == NULL) return(NULL);
7891 switch (ctxt->context->node->type) {
7892 case XML_ELEMENT_NODE:
7893 case XML_TEXT_NODE:
7894 case XML_CDATA_SECTION_NODE:
7895 case XML_ENTITY_REF_NODE:
7896 case XML_ENTITY_NODE:
7897 case XML_PI_NODE:
7898 case XML_COMMENT_NODE:
7899 case XML_NOTATION_NODE:
7900 case XML_DTD_NODE:
7901 case XML_ELEMENT_DECL:
7902 case XML_ATTRIBUTE_DECL:
7903 case XML_XINCLUDE_START:
7904 case XML_XINCLUDE_END:
7905 case XML_ENTITY_DECL:
7906 if (ctxt->context->node->parent == NULL)
7907 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007908 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007909 ((ctxt->context->node->parent->name[0] == ' ') ||
7910 (xmlStrEqual(ctxt->context->node->parent->name,
7911 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007912 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007913 return(ctxt->context->node->parent);
7914 case XML_ATTRIBUTE_NODE: {
7915 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7916
7917 return(att->parent);
7918 }
7919 case XML_DOCUMENT_NODE:
7920 case XML_DOCUMENT_TYPE_NODE:
7921 case XML_DOCUMENT_FRAG_NODE:
7922 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007923#ifdef LIBXML_DOCB_ENABLED
7924 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007925#endif
7926 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007927 case XML_NAMESPACE_DECL: {
7928 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00007929
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007930 if ((ns->next != NULL) &&
7931 (ns->next->type != XML_NAMESPACE_DECL))
7932 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00007933 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007934 }
Owen Taylor3473f882001-02-23 17:55:21 +00007935 }
7936 }
7937 return(NULL);
7938}
7939
7940/**
7941 * xmlXPathNextAncestor:
7942 * @ctxt: the XPath Parser context
7943 * @cur: the current node in the traversal
7944 *
7945 * Traversal function for the "ancestor" direction
7946 * the ancestor axis contains the ancestors of the context node; the ancestors
7947 * of the context node consist of the parent of context node and the parent's
7948 * parent and so on; the nodes are ordered in reverse document order; thus the
7949 * parent is the first node on the axis, and the parent's parent is the second
7950 * node on the axis
7951 *
7952 * Returns the next element following that axis
7953 */
7954xmlNodePtr
7955xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007956 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007957 /*
7958 * the parent of an attribute or namespace node is the element
7959 * to which the attribute or namespace node is attached
7960 * !!!!!!!!!!!!!
7961 */
7962 if (cur == NULL) {
7963 if (ctxt->context->node == NULL) return(NULL);
7964 switch (ctxt->context->node->type) {
7965 case XML_ELEMENT_NODE:
7966 case XML_TEXT_NODE:
7967 case XML_CDATA_SECTION_NODE:
7968 case XML_ENTITY_REF_NODE:
7969 case XML_ENTITY_NODE:
7970 case XML_PI_NODE:
7971 case XML_COMMENT_NODE:
7972 case XML_DTD_NODE:
7973 case XML_ELEMENT_DECL:
7974 case XML_ATTRIBUTE_DECL:
7975 case XML_ENTITY_DECL:
7976 case XML_NOTATION_NODE:
7977 case XML_XINCLUDE_START:
7978 case XML_XINCLUDE_END:
7979 if (ctxt->context->node->parent == NULL)
7980 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007981 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007982 ((ctxt->context->node->parent->name[0] == ' ') ||
7983 (xmlStrEqual(ctxt->context->node->parent->name,
7984 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007985 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007986 return(ctxt->context->node->parent);
7987 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007988 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00007989
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007990 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00007991 }
7992 case XML_DOCUMENT_NODE:
7993 case XML_DOCUMENT_TYPE_NODE:
7994 case XML_DOCUMENT_FRAG_NODE:
7995 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007996#ifdef LIBXML_DOCB_ENABLED
7997 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007998#endif
7999 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008000 case XML_NAMESPACE_DECL: {
8001 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008002
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008003 if ((ns->next != NULL) &&
8004 (ns->next->type != XML_NAMESPACE_DECL))
8005 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00008006 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00008007 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00008008 }
Owen Taylor3473f882001-02-23 17:55:21 +00008009 }
8010 return(NULL);
8011 }
8012 if (cur == ctxt->context->doc->children)
8013 return((xmlNodePtr) ctxt->context->doc);
8014 if (cur == (xmlNodePtr) ctxt->context->doc)
8015 return(NULL);
8016 switch (cur->type) {
8017 case XML_ELEMENT_NODE:
8018 case XML_TEXT_NODE:
8019 case XML_CDATA_SECTION_NODE:
8020 case XML_ENTITY_REF_NODE:
8021 case XML_ENTITY_NODE:
8022 case XML_PI_NODE:
8023 case XML_COMMENT_NODE:
8024 case XML_NOTATION_NODE:
8025 case XML_DTD_NODE:
8026 case XML_ELEMENT_DECL:
8027 case XML_ATTRIBUTE_DECL:
8028 case XML_ENTITY_DECL:
8029 case XML_XINCLUDE_START:
8030 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008031 if (cur->parent == NULL)
8032 return(NULL);
8033 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00008034 ((cur->parent->name[0] == ' ') ||
8035 (xmlStrEqual(cur->parent->name,
8036 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00008037 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008038 return(cur->parent);
8039 case XML_ATTRIBUTE_NODE: {
8040 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
8041
8042 return(att->parent);
8043 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008044 case XML_NAMESPACE_DECL: {
8045 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008046
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008047 if ((ns->next != NULL) &&
8048 (ns->next->type != XML_NAMESPACE_DECL))
8049 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00008050 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00008051 return(NULL);
8052 }
Owen Taylor3473f882001-02-23 17:55:21 +00008053 case XML_DOCUMENT_NODE:
8054 case XML_DOCUMENT_TYPE_NODE:
8055 case XML_DOCUMENT_FRAG_NODE:
8056 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00008057#ifdef LIBXML_DOCB_ENABLED
8058 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00008059#endif
8060 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008061 }
8062 return(NULL);
8063}
8064
8065/**
8066 * xmlXPathNextAncestorOrSelf:
8067 * @ctxt: the XPath Parser context
8068 * @cur: the current node in the traversal
8069 *
8070 * Traversal function for the "ancestor-or-self" direction
8071 * he ancestor-or-self axis contains the context node and ancestors of
8072 * the context node in reverse document order; thus the context node is
8073 * the first node on the axis, and the context node's parent the second;
8074 * parent here is defined the same as with the parent axis.
8075 *
8076 * Returns the next element following that axis
8077 */
8078xmlNodePtr
8079xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008080 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008081 if (cur == NULL)
8082 return(ctxt->context->node);
8083 return(xmlXPathNextAncestor(ctxt, cur));
8084}
8085
8086/**
8087 * xmlXPathNextFollowingSibling:
8088 * @ctxt: the XPath Parser context
8089 * @cur: the current node in the traversal
8090 *
8091 * Traversal function for the "following-sibling" direction
8092 * The following-sibling axis contains the following siblings of the context
8093 * node in document order.
8094 *
8095 * Returns the next element following that axis
8096 */
8097xmlNodePtr
8098xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008099 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008100 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8101 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8102 return(NULL);
8103 if (cur == (xmlNodePtr) ctxt->context->doc)
8104 return(NULL);
8105 if (cur == NULL)
8106 return(ctxt->context->node->next);
8107 return(cur->next);
8108}
8109
8110/**
8111 * xmlXPathNextPrecedingSibling:
8112 * @ctxt: the XPath Parser context
8113 * @cur: the current node in the traversal
8114 *
8115 * Traversal function for the "preceding-sibling" direction
8116 * The preceding-sibling axis contains the preceding siblings of the context
8117 * node in reverse document order; the first preceding sibling is first on the
8118 * axis; the sibling preceding that node is the second on the axis and so on.
8119 *
8120 * Returns the next element following that axis
8121 */
8122xmlNodePtr
8123xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008124 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008125 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8126 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8127 return(NULL);
8128 if (cur == (xmlNodePtr) ctxt->context->doc)
8129 return(NULL);
8130 if (cur == NULL)
8131 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008132 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8133 cur = cur->prev;
8134 if (cur == NULL)
8135 return(ctxt->context->node->prev);
8136 }
Owen Taylor3473f882001-02-23 17:55:21 +00008137 return(cur->prev);
8138}
8139
8140/**
8141 * xmlXPathNextFollowing:
8142 * @ctxt: the XPath Parser context
8143 * @cur: the current node in the traversal
8144 *
8145 * Traversal function for the "following" direction
8146 * The following axis contains all nodes in the same document as the context
8147 * node that are after the context node in document order, excluding any
8148 * descendants and excluding attribute nodes and namespace nodes; the nodes
8149 * are ordered in document order
8150 *
8151 * Returns the next element following that axis
8152 */
8153xmlNodePtr
8154xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008155 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008156 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
8157 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8158 return(cur->children);
8159
8160 if (cur == NULL) {
8161 cur = ctxt->context->node;
8162 if (cur->type == XML_NAMESPACE_DECL)
Daniel Veillard91d19752010-10-15 14:30:52 +02008163 return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008164 if (cur->type == XML_ATTRIBUTE_NODE)
8165 cur = cur->parent;
Daniel Veillard91d19752010-10-15 14:30:52 +02008166 }
Owen Taylor3473f882001-02-23 17:55:21 +00008167 if (cur == NULL) return(NULL) ; /* ERROR */
8168 if (cur->next != NULL) return(cur->next) ;
8169 do {
8170 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00008171 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00008172 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8173 if (cur->next != NULL) return(cur->next);
8174 } while (cur != NULL);
8175 return(cur);
8176}
8177
8178/*
8179 * xmlXPathIsAncestor:
8180 * @ancestor: the ancestor node
8181 * @node: the current node
8182 *
8183 * Check that @ancestor is a @node's ancestor
8184 *
8185 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8186 */
8187static int
8188xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8189 if ((ancestor == NULL) || (node == NULL)) return(0);
8190 /* nodes need to be in the same document */
8191 if (ancestor->doc != node->doc) return(0);
8192 /* avoid searching if ancestor or node is the root node */
8193 if (ancestor == (xmlNodePtr) node->doc) return(1);
8194 if (node == (xmlNodePtr) ancestor->doc) return(0);
8195 while (node->parent != NULL) {
8196 if (node->parent == ancestor)
8197 return(1);
8198 node = node->parent;
8199 }
8200 return(0);
8201}
8202
8203/**
8204 * xmlXPathNextPreceding:
8205 * @ctxt: the XPath Parser context
8206 * @cur: the current node in the traversal
8207 *
8208 * Traversal function for the "preceding" direction
8209 * the preceding axis contains all nodes in the same document as the context
8210 * node that are before the context node in document order, excluding any
8211 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8212 * ordered in reverse document order
8213 *
8214 * Returns the next element following that axis
8215 */
8216xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00008217xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8218{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008219 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008220 if (cur == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008221 cur = ctxt->context->node;
Daniel Veillardea90b892010-10-22 15:50:50 +02008222 if (cur->type == XML_NAMESPACE_DECL)
8223 return(NULL);
8224 if (cur->type == XML_ATTRIBUTE_NODE)
8225 return(cur->parent);
8226 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00008227 if (cur == NULL)
8228 return (NULL);
8229 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8230 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00008231 do {
8232 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008233 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8234 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008235 }
8236
8237 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008238 if (cur == NULL)
8239 return (NULL);
8240 if (cur == ctxt->context->doc->children)
8241 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008242 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00008243 return (cur);
8244}
8245
8246/**
8247 * xmlXPathNextPrecedingInternal:
8248 * @ctxt: the XPath Parser context
8249 * @cur: the current node in the traversal
8250 *
8251 * Traversal function for the "preceding" direction
8252 * the preceding axis contains all nodes in the same document as the context
8253 * node that are before the context node in document order, excluding any
8254 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8255 * ordered in reverse document order
Daniel Veillard45490ae2008-07-29 09:13:19 +00008256 * This is a faster implementation but internal only since it requires a
Daniel Veillardf06307e2001-07-03 10:35:50 +00008257 * state kept in the parser context: ctxt->ancestor.
8258 *
8259 * Returns the next element following that axis
8260 */
8261static xmlNodePtr
8262xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8263 xmlNodePtr cur)
8264{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008265 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008266 if (cur == NULL) {
8267 cur = ctxt->context->node;
8268 if (cur == NULL)
8269 return (NULL);
Daniel Veillardea90b892010-10-22 15:50:50 +02008270 if (cur->type == XML_NAMESPACE_DECL)
8271 return (NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008272 ctxt->ancestor = cur->parent;
8273 }
8274 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8275 cur = cur->prev;
8276 while (cur->prev == NULL) {
8277 cur = cur->parent;
8278 if (cur == NULL)
8279 return (NULL);
8280 if (cur == ctxt->context->doc->children)
8281 return (NULL);
8282 if (cur != ctxt->ancestor)
8283 return (cur);
8284 ctxt->ancestor = cur->parent;
8285 }
8286 cur = cur->prev;
8287 while (cur->last != NULL)
8288 cur = cur->last;
8289 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008290}
8291
8292/**
8293 * xmlXPathNextNamespace:
8294 * @ctxt: the XPath Parser context
8295 * @cur: the current attribute in the traversal
8296 *
8297 * Traversal function for the "namespace" direction
8298 * the namespace axis contains the namespace nodes of the context node;
8299 * the order of nodes on this axis is implementation-defined; the axis will
8300 * be empty unless the context node is an element
8301 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008302 * We keep the XML namespace node at the end of the list.
8303 *
Owen Taylor3473f882001-02-23 17:55:21 +00008304 * Returns the next element following that axis
8305 */
8306xmlNodePtr
8307xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008308 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008309 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00008310 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008311 if (ctxt->context->tmpNsList != NULL)
8312 xmlFree(ctxt->context->tmpNsList);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008313 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00008314 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008315 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00008316 if (ctxt->context->tmpNsList != NULL) {
8317 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8318 ctxt->context->tmpNsNr++;
8319 }
8320 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008321 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008322 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00008323 if (ctxt->context->tmpNsNr > 0) {
8324 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8325 } else {
8326 if (ctxt->context->tmpNsList != NULL)
8327 xmlFree(ctxt->context->tmpNsList);
8328 ctxt->context->tmpNsList = NULL;
8329 return(NULL);
8330 }
Owen Taylor3473f882001-02-23 17:55:21 +00008331}
8332
8333/**
8334 * xmlXPathNextAttribute:
8335 * @ctxt: the XPath Parser context
8336 * @cur: the current attribute in the traversal
8337 *
8338 * Traversal function for the "attribute" direction
8339 * TODO: support DTD inherited default attributes
8340 *
8341 * Returns the next element following that axis
8342 */
8343xmlNodePtr
8344xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008345 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00008346 if (ctxt->context->node == NULL)
8347 return(NULL);
8348 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8349 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008350 if (cur == NULL) {
8351 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8352 return(NULL);
8353 return((xmlNodePtr)ctxt->context->node->properties);
8354 }
8355 return((xmlNodePtr)cur->next);
8356}
8357
8358/************************************************************************
8359 * *
8360 * NodeTest Functions *
8361 * *
8362 ************************************************************************/
8363
Owen Taylor3473f882001-02-23 17:55:21 +00008364#define IS_FUNCTION 200
8365
Owen Taylor3473f882001-02-23 17:55:21 +00008366
8367/************************************************************************
8368 * *
8369 * Implicit tree core function library *
8370 * *
8371 ************************************************************************/
8372
8373/**
8374 * xmlXPathRoot:
8375 * @ctxt: the XPath Parser context
8376 *
8377 * Initialize the context to the root of the document
8378 */
8379void
8380xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008381 if ((ctxt == NULL) || (ctxt->context == NULL))
8382 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008383 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008384 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8385 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008386}
8387
8388/************************************************************************
8389 * *
8390 * The explicit core function library *
8391 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8392 * *
8393 ************************************************************************/
8394
8395
8396/**
8397 * xmlXPathLastFunction:
8398 * @ctxt: the XPath Parser context
8399 * @nargs: the number of arguments
8400 *
8401 * Implement the last() XPath function
8402 * number last()
8403 * The last function returns the number of nodes in the context node list.
8404 */
8405void
8406xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8407 CHECK_ARITY(0);
8408 if (ctxt->context->contextSize >= 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008409 valuePush(ctxt,
8410 xmlXPathCacheNewFloat(ctxt->context,
8411 (double) ctxt->context->contextSize));
Owen Taylor3473f882001-02-23 17:55:21 +00008412#ifdef DEBUG_EXPR
8413 xmlGenericError(xmlGenericErrorContext,
8414 "last() : %d\n", ctxt->context->contextSize);
8415#endif
8416 } else {
8417 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8418 }
8419}
8420
8421/**
8422 * xmlXPathPositionFunction:
8423 * @ctxt: the XPath Parser context
8424 * @nargs: the number of arguments
8425 *
8426 * Implement the position() XPath function
8427 * number position()
8428 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008429 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00008430 * will be equal to last().
8431 */
8432void
8433xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8434 CHECK_ARITY(0);
8435 if (ctxt->context->proximityPosition >= 0) {
8436 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008437 xmlXPathCacheNewFloat(ctxt->context,
8438 (double) ctxt->context->proximityPosition));
Owen Taylor3473f882001-02-23 17:55:21 +00008439#ifdef DEBUG_EXPR
8440 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8441 ctxt->context->proximityPosition);
8442#endif
8443 } else {
8444 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8445 }
8446}
8447
8448/**
8449 * xmlXPathCountFunction:
8450 * @ctxt: the XPath Parser context
8451 * @nargs: the number of arguments
8452 *
8453 * Implement the count() XPath function
8454 * number count(node-set)
8455 */
8456void
8457xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8458 xmlXPathObjectPtr cur;
8459
8460 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008461 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008462 ((ctxt->value->type != XPATH_NODESET) &&
8463 (ctxt->value->type != XPATH_XSLT_TREE)))
8464 XP_ERROR(XPATH_INVALID_TYPE);
8465 cur = valuePop(ctxt);
8466
Daniel Veillard911f49a2001-04-07 15:39:35 +00008467 if ((cur == NULL) || (cur->nodesetval == NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008468 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00008469 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008470 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8471 (double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00008472 } else {
8473 if ((cur->nodesetval->nodeNr != 1) ||
8474 (cur->nodesetval->nodeTab == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008475 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00008476 } else {
8477 xmlNodePtr tmp;
8478 int i = 0;
8479
8480 tmp = cur->nodesetval->nodeTab[0];
8481 if (tmp != NULL) {
8482 tmp = tmp->children;
8483 while (tmp != NULL) {
8484 tmp = tmp->next;
8485 i++;
8486 }
8487 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008488 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
Daniel Veillardfe703322001-08-14 12:18:09 +00008489 }
8490 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008491 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008492}
8493
8494/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008495 * xmlXPathGetElementsByIds:
8496 * @doc: the document
8497 * @ids: a whitespace separated list of IDs
8498 *
8499 * Selects elements by their unique ID.
8500 *
8501 * Returns a node-set of selected elements.
8502 */
8503static xmlNodeSetPtr
8504xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8505 xmlNodeSetPtr ret;
8506 const xmlChar *cur = ids;
8507 xmlChar *ID;
8508 xmlAttrPtr attr;
8509 xmlNodePtr elem = NULL;
8510
Daniel Veillard7a985a12003-07-06 17:57:42 +00008511 if (ids == NULL) return(NULL);
8512
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008513 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00008514 if (ret == NULL)
8515 return(ret);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008516
William M. Brack76e95df2003-10-18 16:20:14 +00008517 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008518 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008519 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00008520 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008521
8522 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00008523 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00008524 /*
8525 * We used to check the fact that the value passed
8526 * was an NCName, but this generated much troubles for
8527 * me and Aleksey Sanin, people blatantly violated that
8528 * constaint, like Visa3D spec.
8529 * if (xmlValidateNCName(ID, 1) == 0)
8530 */
8531 attr = xmlGetID(doc, ID);
8532 if (attr != NULL) {
8533 if (attr->type == XML_ATTRIBUTE_NODE)
8534 elem = attr->parent;
8535 else if (attr->type == XML_ELEMENT_NODE)
8536 elem = (xmlNodePtr) attr;
8537 else
8538 elem = NULL;
8539 if (elem != NULL)
8540 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00008541 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008542 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00008543 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008544
William M. Brack76e95df2003-10-18 16:20:14 +00008545 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008546 ids = cur;
8547 }
8548 return(ret);
8549}
8550
8551/**
Owen Taylor3473f882001-02-23 17:55:21 +00008552 * xmlXPathIdFunction:
8553 * @ctxt: the XPath Parser context
8554 * @nargs: the number of arguments
8555 *
8556 * Implement the id() XPath function
8557 * node-set id(object)
8558 * The id function selects elements by their unique ID
8559 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8560 * then the result is the union of the result of applying id to the
8561 * string value of each of the nodes in the argument node-set. When the
8562 * argument to id is of any other type, the argument is converted to a
8563 * string as if by a call to the string function; the string is split
8564 * into a whitespace-separated list of tokens (whitespace is any sequence
8565 * of characters matching the production S); the result is a node-set
8566 * containing the elements in the same document as the context node that
8567 * have a unique ID equal to any of the tokens in the list.
8568 */
8569void
8570xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008571 xmlChar *tokens;
8572 xmlNodeSetPtr ret;
8573 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00008574
8575 CHECK_ARITY(1);
8576 obj = valuePop(ctxt);
8577 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00008578 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008579 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00008580 int i;
8581
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008582 ret = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +00008583 /*
8584 * FIXME -- in an out-of-memory condition this will behave badly.
8585 * The solution is not clear -- we already popped an item from
8586 * ctxt, so the object is in a corrupt state.
8587 */
Owen Taylor3473f882001-02-23 17:55:21 +00008588
Daniel Veillard911f49a2001-04-07 15:39:35 +00008589 if (obj->nodesetval != NULL) {
8590 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008591 tokens =
8592 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8593 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8594 ret = xmlXPathNodeSetMerge(ret, ns);
8595 xmlXPathFreeNodeSet(ns);
8596 if (tokens != NULL)
8597 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00008598 }
Owen Taylor3473f882001-02-23 17:55:21 +00008599 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008600 xmlXPathReleaseObject(ctxt->context, obj);
8601 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00008602 return;
8603 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008604 obj = xmlXPathCacheConvertString(ctxt->context, obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008605 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008606 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008607 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00008608 return;
8609}
8610
8611/**
8612 * xmlXPathLocalNameFunction:
8613 * @ctxt: the XPath Parser context
8614 * @nargs: the number of arguments
8615 *
8616 * Implement the local-name() XPath function
8617 * string local-name(node-set?)
8618 * The local-name function returns a string containing the local part
8619 * of the name of the node in the argument node-set that is first in
8620 * document order. If the node-set is empty or the first node has no
8621 * name, an empty string is returned. If the argument is omitted it
8622 * defaults to the context node.
8623 */
8624void
8625xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8626 xmlXPathObjectPtr cur;
8627
Daniel Veillarda82b1822004-11-08 16:24:57 +00008628 if (ctxt == NULL) return;
8629
Owen Taylor3473f882001-02-23 17:55:21 +00008630 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008631 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8632 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008633 nargs = 1;
8634 }
8635
8636 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008637 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008638 ((ctxt->value->type != XPATH_NODESET) &&
8639 (ctxt->value->type != XPATH_XSLT_TREE)))
8640 XP_ERROR(XPATH_INVALID_TYPE);
8641 cur = valuePop(ctxt);
8642
Daniel Veillard911f49a2001-04-07 15:39:35 +00008643 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008644 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008645 } else {
8646 int i = 0; /* Should be first in document order !!!!! */
8647 switch (cur->nodesetval->nodeTab[i]->type) {
8648 case XML_ELEMENT_NODE:
8649 case XML_ATTRIBUTE_NODE:
8650 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008651 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008652 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008653 else
8654 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008655 xmlXPathCacheNewString(ctxt->context,
8656 cur->nodesetval->nodeTab[i]->name));
Owen Taylor3473f882001-02-23 17:55:21 +00008657 break;
8658 case XML_NAMESPACE_DECL:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008659 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008660 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8661 break;
8662 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008663 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008664 }
8665 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008666 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008667}
8668
8669/**
8670 * xmlXPathNamespaceURIFunction:
8671 * @ctxt: the XPath Parser context
8672 * @nargs: the number of arguments
8673 *
8674 * Implement the namespace-uri() XPath function
8675 * string namespace-uri(node-set?)
8676 * The namespace-uri function returns a string containing the
8677 * namespace URI of the expanded name of the node in the argument
8678 * node-set that is first in document order. If the node-set is empty,
8679 * the first node has no name, or the expanded name has no namespace
8680 * URI, an empty string is returned. If the argument is omitted it
8681 * defaults to the context node.
8682 */
8683void
8684xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8685 xmlXPathObjectPtr cur;
8686
Daniel Veillarda82b1822004-11-08 16:24:57 +00008687 if (ctxt == NULL) return;
8688
Owen Taylor3473f882001-02-23 17:55:21 +00008689 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008690 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8691 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008692 nargs = 1;
8693 }
8694 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00008695 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008696 ((ctxt->value->type != XPATH_NODESET) &&
8697 (ctxt->value->type != XPATH_XSLT_TREE)))
8698 XP_ERROR(XPATH_INVALID_TYPE);
8699 cur = valuePop(ctxt);
8700
Daniel Veillard911f49a2001-04-07 15:39:35 +00008701 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008702 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008703 } else {
8704 int i = 0; /* Should be first in document order !!!!! */
8705 switch (cur->nodesetval->nodeTab[i]->type) {
8706 case XML_ELEMENT_NODE:
8707 case XML_ATTRIBUTE_NODE:
8708 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008709 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008710 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008711 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008712 cur->nodesetval->nodeTab[i]->ns->href));
8713 break;
8714 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008715 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008716 }
8717 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008718 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008719}
8720
8721/**
8722 * xmlXPathNameFunction:
8723 * @ctxt: the XPath Parser context
8724 * @nargs: the number of arguments
8725 *
8726 * Implement the name() XPath function
8727 * string name(node-set?)
8728 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008729 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00008730 * order. The QName must represent the name with respect to the namespace
8731 * declarations in effect on the node whose name is being represented.
8732 * Typically, this will be the form in which the name occurred in the XML
8733 * source. This need not be the case if there are namespace declarations
8734 * in effect on the node that associate multiple prefixes with the same
8735 * namespace. However, an implementation may include information about
8736 * the original prefix in its representation of nodes; in this case, an
8737 * implementation can ensure that the returned string is always the same
8738 * as the QName used in the XML source. If the argument it omitted it
8739 * defaults to the context node.
8740 * Libxml keep the original prefix so the "real qualified name" used is
8741 * returned.
8742 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008743static void
Daniel Veillard04383752001-07-08 14:27:15 +00008744xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8745{
Owen Taylor3473f882001-02-23 17:55:21 +00008746 xmlXPathObjectPtr cur;
8747
8748 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008749 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8750 ctxt->context->node));
Daniel Veillard04383752001-07-08 14:27:15 +00008751 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008752 }
8753
8754 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00008755 if ((ctxt->value == NULL) ||
8756 ((ctxt->value->type != XPATH_NODESET) &&
8757 (ctxt->value->type != XPATH_XSLT_TREE)))
8758 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00008759 cur = valuePop(ctxt);
8760
Daniel Veillard911f49a2001-04-07 15:39:35 +00008761 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008762 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008763 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00008764 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00008765
Daniel Veillard04383752001-07-08 14:27:15 +00008766 switch (cur->nodesetval->nodeTab[i]->type) {
8767 case XML_ELEMENT_NODE:
8768 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008769 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008770 valuePush(ctxt,
8771 xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008772 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8773 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008774 valuePush(ctxt,
8775 xmlXPathCacheNewString(ctxt->context,
8776 cur->nodesetval->nodeTab[i]->name));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008777 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00008778 xmlChar *fullname;
Daniel Veillard45490ae2008-07-29 09:13:19 +00008779
Daniel Veillardc00cda82003-04-07 10:22:39 +00008780 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8781 cur->nodesetval->nodeTab[i]->ns->prefix,
8782 NULL, 0);
8783 if (fullname == cur->nodesetval->nodeTab[i]->name)
8784 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8785 if (fullname == NULL) {
8786 XP_ERROR(XPATH_MEMORY_ERROR);
8787 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008788 valuePush(ctxt, xmlXPathCacheWrapString(
8789 ctxt->context, fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00008790 }
8791 break;
8792 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008793 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8794 cur->nodesetval->nodeTab[i]));
Daniel Veillard04383752001-07-08 14:27:15 +00008795 xmlXPathLocalNameFunction(ctxt, 1);
8796 }
Owen Taylor3473f882001-02-23 17:55:21 +00008797 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008798 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008799}
8800
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008801
8802/**
Owen Taylor3473f882001-02-23 17:55:21 +00008803 * xmlXPathStringFunction:
8804 * @ctxt: the XPath Parser context
8805 * @nargs: the number of arguments
8806 *
8807 * Implement the string() XPath function
8808 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00008809 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00008810 * - A node-set is converted to a string by returning the value of
8811 * the node in the node-set that is first in document order.
8812 * If the node-set is empty, an empty string is returned.
8813 * - A number is converted to a string as follows
Daniel Veillard45490ae2008-07-29 09:13:19 +00008814 * + NaN is converted to the string NaN
8815 * + positive zero is converted to the string 0
8816 * + negative zero is converted to the string 0
8817 * + positive infinity is converted to the string Infinity
8818 * + negative infinity is converted to the string -Infinity
Owen Taylor3473f882001-02-23 17:55:21 +00008819 * + if the number is an integer, the number is represented in
8820 * decimal form as a Number with no decimal point and no leading
8821 * zeros, preceded by a minus sign (-) if the number is negative
8822 * + otherwise, the number is represented in decimal form as a
8823 * Number including a decimal point with at least one digit
8824 * before the decimal point and at least one digit after the
8825 * decimal point, preceded by a minus sign (-) if the number
8826 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008827 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00008828 * before the decimal point; beyond the one required digit
8829 * after the decimal point there must be as many, but only as
8830 * many, more digits as are needed to uniquely distinguish the
8831 * number from all other IEEE 754 numeric values.
8832 * - The boolean false value is converted to the string false.
8833 * The boolean true value is converted to the string true.
8834 *
8835 * If the argument is omitted, it defaults to a node-set with the
8836 * context node as its only member.
8837 */
8838void
8839xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8840 xmlXPathObjectPtr cur;
8841
Daniel Veillarda82b1822004-11-08 16:24:57 +00008842 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008843 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008844 valuePush(ctxt,
8845 xmlXPathCacheWrapString(ctxt->context,
8846 xmlXPathCastNodeToString(ctxt->context->node)));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008847 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008848 }
8849
8850 CHECK_ARITY(1);
8851 cur = valuePop(ctxt);
8852 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008853 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00008854}
8855
8856/**
8857 * xmlXPathStringLengthFunction:
8858 * @ctxt: the XPath Parser context
8859 * @nargs: the number of arguments
8860 *
8861 * Implement the string-length() XPath function
8862 * number string-length(string?)
8863 * The string-length returns the number of characters in the string
8864 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8865 * the context node converted to a string, in other words the value
8866 * of the context node.
8867 */
8868void
8869xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8870 xmlXPathObjectPtr cur;
8871
8872 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008873 if ((ctxt == NULL) || (ctxt->context == NULL))
8874 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008875 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008876 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008877 } else {
8878 xmlChar *content;
8879
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008880 content = xmlXPathCastNodeToString(ctxt->context->node);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008881 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8882 xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00008883 xmlFree(content);
8884 }
8885 return;
8886 }
8887 CHECK_ARITY(1);
8888 CAST_TO_STRING;
8889 CHECK_TYPE(XPATH_STRING);
8890 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008891 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
Daniel Veillard45490ae2008-07-29 09:13:19 +00008892 xmlUTF8Strlen(cur->stringval)));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008893 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008894}
8895
8896/**
8897 * xmlXPathConcatFunction:
8898 * @ctxt: the XPath Parser context
8899 * @nargs: the number of arguments
8900 *
8901 * Implement the concat() XPath function
8902 * string concat(string, string, string*)
8903 * The concat function returns the concatenation of its arguments.
8904 */
8905void
8906xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8907 xmlXPathObjectPtr cur, newobj;
8908 xmlChar *tmp;
8909
Daniel Veillarda82b1822004-11-08 16:24:57 +00008910 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008911 if (nargs < 2) {
8912 CHECK_ARITY(2);
8913 }
8914
8915 CAST_TO_STRING;
8916 cur = valuePop(ctxt);
8917 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008918 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008919 return;
8920 }
8921 nargs--;
8922
8923 while (nargs > 0) {
8924 CAST_TO_STRING;
8925 newobj = valuePop(ctxt);
8926 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008927 xmlXPathReleaseObject(ctxt->context, newobj);
8928 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008929 XP_ERROR(XPATH_INVALID_TYPE);
8930 }
8931 tmp = xmlStrcat(newobj->stringval, cur->stringval);
8932 newobj->stringval = cur->stringval;
8933 cur->stringval = tmp;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008934 xmlXPathReleaseObject(ctxt->context, newobj);
Owen Taylor3473f882001-02-23 17:55:21 +00008935 nargs--;
8936 }
8937 valuePush(ctxt, cur);
8938}
8939
8940/**
8941 * xmlXPathContainsFunction:
8942 * @ctxt: the XPath Parser context
8943 * @nargs: the number of arguments
8944 *
8945 * Implement the contains() XPath function
8946 * boolean contains(string, string)
8947 * The contains function returns true if the first argument string
8948 * contains the second argument string, and otherwise returns false.
8949 */
8950void
8951xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8952 xmlXPathObjectPtr hay, needle;
8953
8954 CHECK_ARITY(2);
8955 CAST_TO_STRING;
8956 CHECK_TYPE(XPATH_STRING);
8957 needle = valuePop(ctxt);
8958 CAST_TO_STRING;
8959 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008960
Owen Taylor3473f882001-02-23 17:55:21 +00008961 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008962 xmlXPathReleaseObject(ctxt->context, hay);
8963 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008964 XP_ERROR(XPATH_INVALID_TYPE);
8965 }
8966 if (xmlStrstr(hay->stringval, needle->stringval))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008967 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00008968 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008969 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8970 xmlXPathReleaseObject(ctxt->context, hay);
8971 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008972}
8973
8974/**
8975 * xmlXPathStartsWithFunction:
8976 * @ctxt: the XPath Parser context
8977 * @nargs: the number of arguments
8978 *
8979 * Implement the starts-with() XPath function
8980 * boolean starts-with(string, string)
8981 * The starts-with function returns true if the first argument string
8982 * starts with the second argument string, and otherwise returns false.
8983 */
8984void
8985xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8986 xmlXPathObjectPtr hay, needle;
8987 int n;
8988
8989 CHECK_ARITY(2);
8990 CAST_TO_STRING;
8991 CHECK_TYPE(XPATH_STRING);
8992 needle = valuePop(ctxt);
8993 CAST_TO_STRING;
8994 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008995
Owen Taylor3473f882001-02-23 17:55:21 +00008996 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008997 xmlXPathReleaseObject(ctxt->context, hay);
8998 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008999 XP_ERROR(XPATH_INVALID_TYPE);
9000 }
9001 n = xmlStrlen(needle->stringval);
9002 if (xmlStrncmp(hay->stringval, needle->stringval, n))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009003 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009004 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009005 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9006 xmlXPathReleaseObject(ctxt->context, hay);
9007 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00009008}
9009
9010/**
9011 * xmlXPathSubstringFunction:
9012 * @ctxt: the XPath Parser context
9013 * @nargs: the number of arguments
9014 *
9015 * Implement the substring() XPath function
9016 * string substring(string, number, number?)
9017 * The substring function returns the substring of the first argument
9018 * starting at the position specified in the second argument with
9019 * length specified in the third argument. For example,
9020 * substring("12345",2,3) returns "234". If the third argument is not
9021 * specified, it returns the substring starting at the position specified
9022 * in the second argument and continuing to the end of the string. For
9023 * example, substring("12345",2) returns "2345". More precisely, each
9024 * character in the string (see [3.6 Strings]) is considered to have a
9025 * numeric position: the position of the first character is 1, the position
9026 * of the second character is 2 and so on. The returned substring contains
9027 * those characters for which the position of the character is greater than
9028 * or equal to the second argument and, if the third argument is specified,
9029 * less than the sum of the second and third arguments; the comparisons
9030 * and addition used for the above follow the standard IEEE 754 rules. Thus:
Daniel Veillard45490ae2008-07-29 09:13:19 +00009031 * - substring("12345", 1.5, 2.6) returns "234"
9032 * - substring("12345", 0, 3) returns "12"
9033 * - substring("12345", 0 div 0, 3) returns ""
9034 * - substring("12345", 1, 0 div 0) returns ""
9035 * - substring("12345", -42, 1 div 0) returns "12345"
9036 * - substring("12345", -1 div 0, 1 div 0) returns ""
Owen Taylor3473f882001-02-23 17:55:21 +00009037 */
9038void
9039xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9040 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009041 double le=0, in;
9042 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00009043 xmlChar *ret;
9044
Owen Taylor3473f882001-02-23 17:55:21 +00009045 if (nargs < 2) {
9046 CHECK_ARITY(2);
9047 }
9048 if (nargs > 3) {
9049 CHECK_ARITY(3);
9050 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009051 /*
9052 * take care of possible last (position) argument
9053 */
Owen Taylor3473f882001-02-23 17:55:21 +00009054 if (nargs == 3) {
9055 CAST_TO_NUMBER;
9056 CHECK_TYPE(XPATH_NUMBER);
9057 len = valuePop(ctxt);
9058 le = len->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009059 xmlXPathReleaseObject(ctxt->context, len);
Owen Taylor3473f882001-02-23 17:55:21 +00009060 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009061
Owen Taylor3473f882001-02-23 17:55:21 +00009062 CAST_TO_NUMBER;
9063 CHECK_TYPE(XPATH_NUMBER);
9064 start = valuePop(ctxt);
9065 in = start->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009066 xmlXPathReleaseObject(ctxt->context, start);
Owen Taylor3473f882001-02-23 17:55:21 +00009067 CAST_TO_STRING;
9068 CHECK_TYPE(XPATH_STRING);
9069 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00009070 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00009071
Daniel Veillard97ac1312001-05-30 19:14:17 +00009072 /*
9073 * If last pos not present, calculate last position
9074 */
Daniel Veillard9e412302002-06-10 15:59:44 +00009075 if (nargs != 3) {
9076 le = (double)m;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009077 if (in < 1.0)
Daniel Veillard9e412302002-06-10 15:59:44 +00009078 in = 1.0;
9079 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00009080
Daniel Veillard45490ae2008-07-29 09:13:19 +00009081 /* Need to check for the special cases where either
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009082 * the index is NaN, the length is NaN, or both
9083 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00009084 */
Daniel Veillard48b3eb22009-03-25 09:51:19 +00009085 if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009086 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00009087 * To meet the requirements of the spec, the arguments
Daniel Veillard45490ae2008-07-29 09:13:19 +00009088 * must be converted to integer format before
Daniel Veillard9e412302002-06-10 15:59:44 +00009089 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009090 *
Daniel Veillard9e412302002-06-10 15:59:44 +00009091 * First we go to integer form, rounding up
9092 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009093 */
9094 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00009095 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00009096
Daniel Veillard9e412302002-06-10 15:59:44 +00009097 if (xmlXPathIsInf(le) == 1) {
9098 l = m;
9099 if (i < 1)
9100 i = 1;
9101 }
9102 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9103 l = 0;
9104 else {
9105 l = (int) le;
9106 if (((double)l)+0.5 <= le) l++;
9107 }
9108
9109 /* Now we normalize inidices */
9110 i -= 1;
9111 l += i;
9112 if (i < 0)
9113 i = 0;
9114 if (l > m)
9115 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00009116
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009117 /* number of chars to copy */
9118 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00009119
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009120 ret = xmlUTF8Strsub(str->stringval, i, l);
9121 }
9122 else {
9123 ret = NULL;
9124 }
Owen Taylor3473f882001-02-23 17:55:21 +00009125 if (ret == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009126 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00009127 else {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009128 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009129 xmlFree(ret);
9130 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009131 xmlXPathReleaseObject(ctxt->context, str);
Owen Taylor3473f882001-02-23 17:55:21 +00009132}
9133
9134/**
9135 * xmlXPathSubstringBeforeFunction:
9136 * @ctxt: the XPath Parser context
9137 * @nargs: the number of arguments
9138 *
9139 * Implement the substring-before() XPath function
9140 * string substring-before(string, string)
9141 * The substring-before function returns the substring of the first
9142 * argument string that precedes the first occurrence of the second
9143 * argument string in the first argument string, or the empty string
9144 * if the first argument string does not contain the second argument
9145 * string. For example, substring-before("1999/04/01","/") returns 1999.
9146 */
9147void
9148xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9149 xmlXPathObjectPtr str;
9150 xmlXPathObjectPtr find;
Daniel Veillardade10f22012-07-12 09:43:27 +08009151 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009152 const xmlChar *point;
9153 int offset;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009154
Owen Taylor3473f882001-02-23 17:55:21 +00009155 CHECK_ARITY(2);
9156 CAST_TO_STRING;
9157 find = valuePop(ctxt);
9158 CAST_TO_STRING;
9159 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009160
Daniel Veillardade10f22012-07-12 09:43:27 +08009161 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009162 if (target) {
9163 point = xmlStrstr(str->stringval, find->stringval);
9164 if (point) {
9165 offset = (int)(point - str->stringval);
Daniel Veillardade10f22012-07-12 09:43:27 +08009166 xmlBufAdd(target, str->stringval, offset);
Owen Taylor3473f882001-02-23 17:55:21 +00009167 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009168 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009169 xmlBufContent(target)));
9170 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009171 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009172 xmlXPathReleaseObject(ctxt->context, str);
9173 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009174}
9175
9176/**
9177 * xmlXPathSubstringAfterFunction:
9178 * @ctxt: the XPath Parser context
9179 * @nargs: the number of arguments
9180 *
9181 * Implement the substring-after() XPath function
9182 * string substring-after(string, string)
9183 * The substring-after function returns the substring of the first
9184 * argument string that follows the first occurrence of the second
9185 * argument string in the first argument string, or the empty stringi
9186 * if the first argument string does not contain the second argument
9187 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9188 * and substring-after("1999/04/01","19") returns 99/04/01.
9189 */
9190void
9191xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9192 xmlXPathObjectPtr str;
9193 xmlXPathObjectPtr find;
Daniel Veillardade10f22012-07-12 09:43:27 +08009194 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009195 const xmlChar *point;
9196 int offset;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009197
Owen Taylor3473f882001-02-23 17:55:21 +00009198 CHECK_ARITY(2);
9199 CAST_TO_STRING;
9200 find = valuePop(ctxt);
9201 CAST_TO_STRING;
9202 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009203
Daniel Veillardade10f22012-07-12 09:43:27 +08009204 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009205 if (target) {
9206 point = xmlStrstr(str->stringval, find->stringval);
9207 if (point) {
9208 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
Daniel Veillardade10f22012-07-12 09:43:27 +08009209 xmlBufAdd(target, &str->stringval[offset],
Owen Taylor3473f882001-02-23 17:55:21 +00009210 xmlStrlen(str->stringval) - offset);
9211 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009212 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009213 xmlBufContent(target)));
9214 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009215 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009216 xmlXPathReleaseObject(ctxt->context, str);
9217 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009218}
9219
9220/**
9221 * xmlXPathNormalizeFunction:
9222 * @ctxt: the XPath Parser context
9223 * @nargs: the number of arguments
9224 *
9225 * Implement the normalize-space() XPath function
9226 * string normalize-space(string?)
9227 * The normalize-space function returns the argument string with white
9228 * space normalized by stripping leading and trailing whitespace
9229 * and replacing sequences of whitespace characters by a single
9230 * space. Whitespace characters are the same allowed by the S production
9231 * in XML. If the argument is omitted, it defaults to the context
9232 * node converted to a string, in other words the value of the context node.
9233 */
9234void
9235xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9236 xmlXPathObjectPtr obj = NULL;
9237 xmlChar *source = NULL;
Daniel Veillardade10f22012-07-12 09:43:27 +08009238 xmlBufPtr target;
Owen Taylor3473f882001-02-23 17:55:21 +00009239 xmlChar blank;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009240
Daniel Veillarda82b1822004-11-08 16:24:57 +00009241 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009242 if (nargs == 0) {
9243 /* Use current context node */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009244 valuePush(ctxt,
9245 xmlXPathCacheWrapString(ctxt->context,
9246 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00009247 nargs = 1;
9248 }
9249
9250 CHECK_ARITY(1);
9251 CAST_TO_STRING;
9252 CHECK_TYPE(XPATH_STRING);
9253 obj = valuePop(ctxt);
9254 source = obj->stringval;
9255
Daniel Veillardade10f22012-07-12 09:43:27 +08009256 target = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00009257 if (target && source) {
Daniel Veillard45490ae2008-07-29 09:13:19 +00009258
Owen Taylor3473f882001-02-23 17:55:21 +00009259 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00009260 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00009261 source++;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009262
Owen Taylor3473f882001-02-23 17:55:21 +00009263 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9264 blank = 0;
9265 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00009266 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009267 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00009268 } else {
9269 if (blank) {
Daniel Veillardade10f22012-07-12 09:43:27 +08009270 xmlBufAdd(target, &blank, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00009271 blank = 0;
9272 }
Daniel Veillardade10f22012-07-12 09:43:27 +08009273 xmlBufAdd(target, source, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00009274 }
9275 source++;
9276 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009277 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009278 xmlBufContent(target)));
9279 xmlBufFree(target);
Owen Taylor3473f882001-02-23 17:55:21 +00009280 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009281 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00009282}
9283
9284/**
9285 * xmlXPathTranslateFunction:
9286 * @ctxt: the XPath Parser context
9287 * @nargs: the number of arguments
9288 *
9289 * Implement the translate() XPath function
9290 * string translate(string, string, string)
9291 * The translate function returns the first argument string with
9292 * occurrences of characters in the second argument string replaced
9293 * by the character at the corresponding position in the third argument
9294 * string. For example, translate("bar","abc","ABC") returns the string
9295 * BAr. If there is a character in the second argument string with no
9296 * character at a corresponding position in the third argument string
9297 * (because the second argument string is longer than the third argument
9298 * string), then occurrences of that character in the first argument
9299 * string are removed. For example, translate("--aaa--","abc-","ABC")
9300 * returns "AAA". If a character occurs more than once in second
9301 * argument string, then the first occurrence determines the replacement
9302 * character. If the third argument string is longer than the second
9303 * argument string, then excess characters are ignored.
9304 */
9305void
9306xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00009307 xmlXPathObjectPtr str;
9308 xmlXPathObjectPtr from;
9309 xmlXPathObjectPtr to;
Daniel Veillardade10f22012-07-12 09:43:27 +08009310 xmlBufPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009311 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009312 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00009313 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009314 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00009315
Daniel Veillarde043ee12001-04-16 14:08:07 +00009316 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00009317
Daniel Veillarde043ee12001-04-16 14:08:07 +00009318 CAST_TO_STRING;
9319 to = valuePop(ctxt);
9320 CAST_TO_STRING;
9321 from = valuePop(ctxt);
9322 CAST_TO_STRING;
9323 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009324
Daniel Veillardade10f22012-07-12 09:43:27 +08009325 target = xmlBufCreate();
Daniel Veillarde043ee12001-04-16 14:08:07 +00009326 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009327 max = xmlUTF8Strlen(to->stringval);
9328 for (cptr = str->stringval; (ch=*cptr); ) {
9329 offset = xmlUTF8Strloc(from->stringval, cptr);
9330 if (offset >= 0) {
9331 if (offset < max) {
9332 point = xmlUTF8Strpos(to->stringval, offset);
9333 if (point)
Daniel Veillardade10f22012-07-12 09:43:27 +08009334 xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
Daniel Veillard97ac1312001-05-30 19:14:17 +00009335 }
9336 } else
Daniel Veillardade10f22012-07-12 09:43:27 +08009337 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
Daniel Veillard97ac1312001-05-30 19:14:17 +00009338
9339 /* Step to next character in input */
9340 cptr++;
9341 if ( ch & 0x80 ) {
9342 /* if not simple ascii, verify proper format */
9343 if ( (ch & 0xc0) != 0xc0 ) {
9344 xmlGenericError(xmlGenericErrorContext,
9345 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08009346 /* not asserting an XPath error is probably better */
Daniel Veillard97ac1312001-05-30 19:14:17 +00009347 break;
9348 }
9349 /* then skip over remaining bytes for this char */
9350 while ( (ch <<= 1) & 0x80 )
9351 if ( (*cptr++ & 0xc0) != 0x80 ) {
9352 xmlGenericError(xmlGenericErrorContext,
9353 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
Daniel Veillard1d4526f2011-10-11 16:34:34 +08009354 /* not asserting an XPath error is probably better */
Daniel Veillard97ac1312001-05-30 19:14:17 +00009355 break;
9356 }
9357 if (ch & 0x80) /* must have had error encountered */
9358 break;
9359 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00009360 }
Owen Taylor3473f882001-02-23 17:55:21 +00009361 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009362 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +08009363 xmlBufContent(target)));
9364 xmlBufFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009365 xmlXPathReleaseObject(ctxt->context, str);
9366 xmlXPathReleaseObject(ctxt->context, from);
9367 xmlXPathReleaseObject(ctxt->context, to);
Owen Taylor3473f882001-02-23 17:55:21 +00009368}
9369
9370/**
9371 * xmlXPathBooleanFunction:
9372 * @ctxt: the XPath Parser context
9373 * @nargs: the number of arguments
9374 *
9375 * Implement the boolean() XPath function
9376 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00009377 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00009378 * - a number is true if and only if it is neither positive or
9379 * negative zero nor NaN
9380 * - a node-set is true if and only if it is non-empty
9381 * - a string is true if and only if its length is non-zero
9382 */
9383void
9384xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9385 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00009386
9387 CHECK_ARITY(1);
9388 cur = valuePop(ctxt);
9389 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009390 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009391 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009392}
9393
9394/**
9395 * xmlXPathNotFunction:
9396 * @ctxt: the XPath Parser context
9397 * @nargs: the number of arguments
9398 *
9399 * Implement the not() XPath function
9400 * boolean not(boolean)
9401 * The not function returns true if its argument is false,
9402 * and false otherwise.
9403 */
9404void
9405xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9406 CHECK_ARITY(1);
9407 CAST_TO_BOOLEAN;
9408 CHECK_TYPE(XPATH_BOOLEAN);
9409 ctxt->value->boolval = ! ctxt->value->boolval;
9410}
9411
9412/**
9413 * xmlXPathTrueFunction:
9414 * @ctxt: the XPath Parser context
9415 * @nargs: the number of arguments
9416 *
9417 * Implement the true() XPath function
9418 * boolean true()
9419 */
9420void
9421xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9422 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009423 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009424}
9425
9426/**
9427 * xmlXPathFalseFunction:
9428 * @ctxt: the XPath Parser context
9429 * @nargs: the number of arguments
9430 *
9431 * Implement the false() XPath function
9432 * boolean false()
9433 */
9434void
9435xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9436 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009437 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009438}
9439
9440/**
9441 * xmlXPathLangFunction:
9442 * @ctxt: the XPath Parser context
9443 * @nargs: the number of arguments
9444 *
9445 * Implement the lang() XPath function
9446 * boolean lang(string)
9447 * The lang function returns true or false depending on whether the
9448 * language of the context node as specified by xml:lang attributes
9449 * is the same as or is a sublanguage of the language specified by
9450 * the argument string. The language of the context node is determined
9451 * by the value of the xml:lang attribute on the context node, or, if
9452 * the context node has no xml:lang attribute, by the value of the
9453 * xml:lang attribute on the nearest ancestor of the context node that
9454 * has an xml:lang attribute. If there is no such attribute, then lang
9455 * returns false. If there is such an attribute, then lang returns
9456 * true if the attribute value is equal to the argument ignoring case,
9457 * or if there is some suffix starting with - such that the attribute
9458 * value is equal to the argument ignoring that suffix of the attribute
9459 * value and ignoring case.
9460 */
9461void
9462xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009463 xmlXPathObjectPtr val = NULL;
9464 const xmlChar *theLang = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009465 const xmlChar *lang;
9466 int ret = 0;
9467 int i;
9468
9469 CHECK_ARITY(1);
9470 CAST_TO_STRING;
9471 CHECK_TYPE(XPATH_STRING);
9472 val = valuePop(ctxt);
9473 lang = val->stringval;
9474 theLang = xmlNodeGetLang(ctxt->context->node);
9475 if ((theLang != NULL) && (lang != NULL)) {
9476 for (i = 0;lang[i] != 0;i++)
9477 if (toupper(lang[i]) != toupper(theLang[i]))
9478 goto not_equal;
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009479 if ((theLang[i] == 0) || (theLang[i] == '-'))
9480 ret = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009481 }
9482not_equal:
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009483 if (theLang != NULL)
9484 xmlFree((void *)theLang);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009485
9486 xmlXPathReleaseObject(ctxt->context, val);
9487 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009488}
9489
9490/**
9491 * xmlXPathNumberFunction:
9492 * @ctxt: the XPath Parser context
9493 * @nargs: the number of arguments
9494 *
9495 * Implement the number() XPath function
9496 * number number(object?)
9497 */
9498void
9499xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9500 xmlXPathObjectPtr cur;
9501 double res;
9502
Daniel Veillarda82b1822004-11-08 16:24:57 +00009503 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009504 if (nargs == 0) {
9505 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009506 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
Owen Taylor3473f882001-02-23 17:55:21 +00009507 } else {
9508 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9509
9510 res = xmlXPathStringEvalNumber(content);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009511 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
Owen Taylor3473f882001-02-23 17:55:21 +00009512 xmlFree(content);
9513 }
9514 return;
9515 }
9516
9517 CHECK_ARITY(1);
9518 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009519 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00009520}
9521
9522/**
9523 * xmlXPathSumFunction:
9524 * @ctxt: the XPath Parser context
9525 * @nargs: the number of arguments
9526 *
9527 * Implement the sum() XPath function
9528 * number sum(node-set)
9529 * The sum function returns the sum of the values of the nodes in
9530 * the argument node-set.
9531 */
9532void
9533xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9534 xmlXPathObjectPtr cur;
9535 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009536 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00009537
9538 CHECK_ARITY(1);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009539 if ((ctxt->value == NULL) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009540 ((ctxt->value->type != XPATH_NODESET) &&
9541 (ctxt->value->type != XPATH_XSLT_TREE)))
9542 XP_ERROR(XPATH_INVALID_TYPE);
9543 cur = valuePop(ctxt);
9544
William M. Brack08171912003-12-29 02:52:11 +00009545 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009546 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9547 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00009548 }
9549 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009550 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9551 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009552}
9553
William M. Brack3d426662005-04-19 14:40:28 +00009554/*
9555 * To assure working code on multiple platforms, we want to only depend
9556 * upon the characteristic truncation of converting a floating point value
9557 * to an integer. Unfortunately, because of the different storage sizes
9558 * of our internal floating point value (double) and integer (int), we
9559 * can't directly convert (see bug 301162). This macro is a messy
9560 * 'workaround'
9561 */
9562#define XTRUNC(f, v) \
9563 f = fmod((v), INT_MAX); \
9564 f = (v) - (f) + (double)((int)(f));
9565
Owen Taylor3473f882001-02-23 17:55:21 +00009566/**
9567 * xmlXPathFloorFunction:
9568 * @ctxt: the XPath Parser context
9569 * @nargs: the number of arguments
9570 *
9571 * Implement the floor() XPath function
9572 * number floor(number)
9573 * The floor function returns the largest (closest to positive infinity)
9574 * number that is not greater than the argument and that is an integer.
9575 */
9576void
9577xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009578 double f;
9579
Owen Taylor3473f882001-02-23 17:55:21 +00009580 CHECK_ARITY(1);
9581 CAST_TO_NUMBER;
9582 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009583
William M. Brack3d426662005-04-19 14:40:28 +00009584 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009585 if (f != ctxt->value->floatval) {
9586 if (ctxt->value->floatval > 0)
9587 ctxt->value->floatval = f;
9588 else
9589 ctxt->value->floatval = f - 1;
9590 }
Owen Taylor3473f882001-02-23 17:55:21 +00009591}
9592
9593/**
9594 * xmlXPathCeilingFunction:
9595 * @ctxt: the XPath Parser context
9596 * @nargs: the number of arguments
9597 *
9598 * Implement the ceiling() XPath function
9599 * number ceiling(number)
9600 * The ceiling function returns the smallest (closest to negative infinity)
9601 * number that is not less than the argument and that is an integer.
9602 */
9603void
9604xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9605 double f;
9606
9607 CHECK_ARITY(1);
9608 CAST_TO_NUMBER;
9609 CHECK_TYPE(XPATH_NUMBER);
9610
9611#if 0
9612 ctxt->value->floatval = ceil(ctxt->value->floatval);
9613#else
William M. Brack3d426662005-04-19 14:40:28 +00009614 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009615 if (f != ctxt->value->floatval) {
9616 if (ctxt->value->floatval > 0)
9617 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009618 else {
9619 if (ctxt->value->floatval < 0 && f == 0)
9620 ctxt->value->floatval = xmlXPathNZERO;
9621 else
9622 ctxt->value->floatval = f;
9623 }
9624
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009625 }
Owen Taylor3473f882001-02-23 17:55:21 +00009626#endif
9627}
9628
9629/**
9630 * xmlXPathRoundFunction:
9631 * @ctxt: the XPath Parser context
9632 * @nargs: the number of arguments
9633 *
9634 * Implement the round() XPath function
9635 * number round(number)
9636 * The round function returns the number that is closest to the
9637 * argument and that is an integer. If there are two such numbers,
9638 * then the one that is even is returned.
9639 */
9640void
9641xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9642 double f;
9643
9644 CHECK_ARITY(1);
9645 CAST_TO_NUMBER;
9646 CHECK_TYPE(XPATH_NUMBER);
9647
Daniel Veillardcda96922001-08-21 10:56:31 +00009648 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9649 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9650 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009651 (ctxt->value->floatval == 0.0))
9652 return;
9653
William M. Brack3d426662005-04-19 14:40:28 +00009654 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009655 if (ctxt->value->floatval < 0) {
9656 if (ctxt->value->floatval < f - 0.5)
9657 ctxt->value->floatval = f - 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009658 else
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009659 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009660 if (ctxt->value->floatval == 0)
9661 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009662 } else {
9663 if (ctxt->value->floatval < f + 0.5)
9664 ctxt->value->floatval = f;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009665 else
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009666 ctxt->value->floatval = f + 1;
9667 }
Owen Taylor3473f882001-02-23 17:55:21 +00009668}
9669
9670/************************************************************************
9671 * *
9672 * The Parser *
9673 * *
9674 ************************************************************************/
9675
9676/*
William M. Brack08171912003-12-29 02:52:11 +00009677 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00009678 * implementation.
9679 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009680static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009681static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009682static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009683static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00009684static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9685 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00009686
9687/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00009688 * xmlXPathCurrentChar:
9689 * @ctxt: the XPath parser context
9690 * @cur: pointer to the beginning of the char
9691 * @len: pointer to the length of the char read
9692 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009693 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00009694 * bytes in the input buffer.
9695 *
Daniel Veillard60087f32001-10-10 09:45:09 +00009696 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00009697 */
9698
9699static int
9700xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9701 unsigned char c;
9702 unsigned int val;
9703 const xmlChar *cur;
9704
9705 if (ctxt == NULL)
9706 return(0);
9707 cur = ctxt->cur;
9708
9709 /*
9710 * We are supposed to handle UTF8, check it's valid
9711 * From rfc2044: encoding of the Unicode values on UTF-8:
9712 *
9713 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9714 * 0000 0000-0000 007F 0xxxxxxx
9715 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
Daniel Veillard45490ae2008-07-29 09:13:19 +00009716 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
Daniel Veillard61d80a22001-04-27 17:13:01 +00009717 *
9718 * Check for the 0x110000 limit too
9719 */
9720 c = *cur;
9721 if (c & 0x80) {
9722 if ((cur[1] & 0xc0) != 0x80)
9723 goto encoding_error;
9724 if ((c & 0xe0) == 0xe0) {
9725
9726 if ((cur[2] & 0xc0) != 0x80)
9727 goto encoding_error;
9728 if ((c & 0xf0) == 0xf0) {
9729 if (((c & 0xf8) != 0xf0) ||
9730 ((cur[3] & 0xc0) != 0x80))
9731 goto encoding_error;
9732 /* 4-byte code */
9733 *len = 4;
9734 val = (cur[0] & 0x7) << 18;
9735 val |= (cur[1] & 0x3f) << 12;
9736 val |= (cur[2] & 0x3f) << 6;
9737 val |= cur[3] & 0x3f;
9738 } else {
9739 /* 3-byte code */
9740 *len = 3;
9741 val = (cur[0] & 0xf) << 12;
9742 val |= (cur[1] & 0x3f) << 6;
9743 val |= cur[2] & 0x3f;
9744 }
9745 } else {
9746 /* 2-byte code */
9747 *len = 2;
9748 val = (cur[0] & 0x1f) << 6;
9749 val |= cur[1] & 0x3f;
9750 }
9751 if (!IS_CHAR(val)) {
9752 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
Daniel Veillard45490ae2008-07-29 09:13:19 +00009753 }
Daniel Veillard61d80a22001-04-27 17:13:01 +00009754 return(val);
9755 } else {
9756 /* 1-byte code */
9757 *len = 1;
9758 return((int) *cur);
9759 }
9760encoding_error:
9761 /*
William M. Brack08171912003-12-29 02:52:11 +00009762 * If we detect an UTF8 error that probably means that the
9763 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00009764 * declaration header. Report the error and switch the encoding
9765 * to ISO-Latin-1 (if you don't like this policy, just declare the
9766 * encoding !)
9767 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00009768 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00009769 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009770}
9771
9772/**
Owen Taylor3473f882001-02-23 17:55:21 +00009773 * xmlXPathParseNCName:
9774 * @ctxt: the XPath Parser context
9775 *
9776 * parse an XML namespace non qualified name.
9777 *
9778 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9779 *
9780 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9781 * CombiningChar | Extender
9782 *
9783 * Returns the namespace name or NULL
9784 */
9785
9786xmlChar *
9787xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00009788 const xmlChar *in;
9789 xmlChar *ret;
9790 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009791
Daniel Veillarda82b1822004-11-08 16:24:57 +00009792 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00009793 /*
9794 * Accelerator for simple ASCII names
9795 */
9796 in = ctxt->cur;
9797 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9798 ((*in >= 0x41) && (*in <= 0x5A)) ||
9799 (*in == '_')) {
9800 in++;
9801 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9802 ((*in >= 0x41) && (*in <= 0x5A)) ||
9803 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00009804 (*in == '_') || (*in == '.') ||
9805 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00009806 in++;
9807 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9808 (*in == '[') || (*in == ']') || (*in == ':') ||
9809 (*in == '@') || (*in == '*')) {
9810 count = in - ctxt->cur;
9811 if (count == 0)
9812 return(NULL);
9813 ret = xmlStrndup(ctxt->cur, count);
9814 ctxt->cur = in;
9815 return(ret);
9816 }
9817 }
9818 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009819}
9820
Daniel Veillard2156a562001-04-28 12:24:34 +00009821
Owen Taylor3473f882001-02-23 17:55:21 +00009822/**
9823 * xmlXPathParseQName:
9824 * @ctxt: the XPath Parser context
Daniel Veillard45490ae2008-07-29 09:13:19 +00009825 * @prefix: a xmlChar **
Owen Taylor3473f882001-02-23 17:55:21 +00009826 *
9827 * parse an XML qualified name
9828 *
9829 * [NS 5] QName ::= (Prefix ':')? LocalPart
9830 *
9831 * [NS 6] Prefix ::= NCName
9832 *
9833 * [NS 7] LocalPart ::= NCName
9834 *
9835 * Returns the function returns the local part, and prefix is updated
9836 * to get the Prefix if any.
9837 */
9838
Daniel Veillard56a4cb82001-03-24 17:00:36 +00009839static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00009840xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9841 xmlChar *ret = NULL;
9842
9843 *prefix = NULL;
9844 ret = xmlXPathParseNCName(ctxt);
Daniel Veillard074f37e2008-09-01 13:38:22 +00009845 if (ret && CUR == ':') {
Owen Taylor3473f882001-02-23 17:55:21 +00009846 *prefix = ret;
9847 NEXT;
9848 ret = xmlXPathParseNCName(ctxt);
9849 }
9850 return(ret);
9851}
9852
9853/**
9854 * xmlXPathParseName:
9855 * @ctxt: the XPath Parser context
9856 *
9857 * parse an XML name
9858 *
9859 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9860 * CombiningChar | Extender
9861 *
9862 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9863 *
9864 * Returns the namespace name or NULL
9865 */
9866
9867xmlChar *
9868xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009869 const xmlChar *in;
9870 xmlChar *ret;
9871 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009872
Daniel Veillarda82b1822004-11-08 16:24:57 +00009873 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009874 /*
9875 * Accelerator for simple ASCII names
9876 */
9877 in = ctxt->cur;
9878 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9879 ((*in >= 0x41) && (*in <= 0x5A)) ||
9880 (*in == '_') || (*in == ':')) {
9881 in++;
9882 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9883 ((*in >= 0x41) && (*in <= 0x5A)) ||
9884 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00009885 (*in == '_') || (*in == '-') ||
9886 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00009887 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00009888 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009889 count = in - ctxt->cur;
9890 ret = xmlStrndup(ctxt->cur, count);
9891 ctxt->cur = in;
9892 return(ret);
9893 }
9894 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009895 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009896}
9897
Daniel Veillard61d80a22001-04-27 17:13:01 +00009898static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00009899xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009900 xmlChar buf[XML_MAX_NAMELEN + 5];
9901 int len = 0, l;
9902 int c;
9903
9904 /*
9905 * Handler for more complex cases
9906 */
9907 c = CUR_CHAR(l);
9908 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00009909 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9910 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00009911 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00009912 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009913 return(NULL);
9914 }
9915
9916 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9917 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9918 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00009919 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009920 (IS_COMBINING(c)) ||
9921 (IS_EXTENDER(c)))) {
9922 COPY_BUF(l,buf,len,c);
9923 NEXTL(l);
9924 c = CUR_CHAR(l);
9925 if (len >= XML_MAX_NAMELEN) {
9926 /*
9927 * Okay someone managed to make a huge name, so he's ready to pay
9928 * for the processing speed.
9929 */
9930 xmlChar *buffer;
9931 int max = len * 2;
Daniel Veillard45490ae2008-07-29 09:13:19 +00009932
Daniel Veillard3c908dc2003-04-19 00:07:51 +00009933 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009934 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009935 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009936 }
9937 memcpy(buffer, buf, len);
9938 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9939 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +00009940 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009941 (IS_COMBINING(c)) ||
9942 (IS_EXTENDER(c))) {
9943 if (len + 10 > max) {
9944 max *= 2;
9945 buffer = (xmlChar *) xmlRealloc(buffer,
9946 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009947 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009948 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009949 }
9950 }
9951 COPY_BUF(l,buffer,len,c);
9952 NEXTL(l);
9953 c = CUR_CHAR(l);
9954 }
9955 buffer[len] = 0;
9956 return(buffer);
9957 }
9958 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009959 if (len == 0)
9960 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009961 return(xmlStrndup(buf, len));
9962}
Daniel Veillard3cd72402002-05-13 10:33:30 +00009963
9964#define MAX_FRAC 20
9965
William M. Brack372a4452004-02-17 13:09:23 +00009966/*
9967 * These are used as divisors for the fractional part of a number.
9968 * Since the table includes 1.0 (representing '0' fractional digits),
9969 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
9970 */
9971static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +00009972 1.0, 10.0, 100.0, 1000.0, 10000.0,
9973 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
9974 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
9975 100000000000000.0,
9976 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +00009977 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +00009978};
9979
Owen Taylor3473f882001-02-23 17:55:21 +00009980/**
9981 * xmlXPathStringEvalNumber:
9982 * @str: A string to scan
9983 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00009984 * [30a] Float ::= Number ('e' Digits?)?
9985 *
Owen Taylor3473f882001-02-23 17:55:21 +00009986 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard45490ae2008-07-29 09:13:19 +00009987 * | '.' Digits
Owen Taylor3473f882001-02-23 17:55:21 +00009988 * [31] Digits ::= [0-9]+
9989 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009990 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00009991 * In complement of the Number expression, this function also handles
9992 * negative values : '-' Number.
9993 *
9994 * Returns the double value.
9995 */
9996double
9997xmlXPathStringEvalNumber(const xmlChar *str) {
9998 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00009999 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010000 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010001 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010002 int exponent = 0;
10003 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010004#ifdef __GNUC__
10005 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010006 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010007#endif
Daniel Veillardeca82812002-04-24 11:42:02 +000010008 if (cur == NULL) return(0);
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 != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
10011 return(xmlXPathNAN);
10012 }
10013 if (*cur == '-') {
10014 isneg = 1;
10015 cur++;
10016 }
Daniel Veillardb06c6142001-08-27 14:26:30 +000010017
10018#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010019 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010020 * tmp/temp is a workaround against a gcc compiler bug
10021 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010022 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010023 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010024 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010025 ret = ret * 10;
10026 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +000010027 ok = 1;
10028 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +000010029 temp = (double) tmp;
10030 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010031 }
Daniel Veillardb06c6142001-08-27 14:26:30 +000010032#else
Daniel Veillard7b416132002-03-07 08:36:03 +000010033 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +000010034 while ((*cur >= '0') && (*cur <= '9')) {
10035 ret = ret * 10 + (*cur - '0');
10036 ok = 1;
10037 cur++;
10038 }
10039#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010040
Owen Taylor3473f882001-02-23 17:55:21 +000010041 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +000010042 int v, frac = 0;
10043 double fraction = 0;
10044
Owen Taylor3473f882001-02-23 17:55:21 +000010045 cur++;
10046 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10047 return(xmlXPathNAN);
10048 }
Daniel Veillard3cd72402002-05-13 10:33:30 +000010049 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
10050 v = (*cur - '0');
10051 fraction = fraction * 10 + v;
10052 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010053 cur++;
10054 }
Daniel Veillard3cd72402002-05-13 10:33:30 +000010055 fraction /= my_pow10[frac];
10056 ret = ret + fraction;
10057 while ((*cur >= '0') && (*cur <= '9'))
10058 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010059 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010060 if ((*cur == 'e') || (*cur == 'E')) {
10061 cur++;
10062 if (*cur == '-') {
10063 is_exponent_negative = 1;
10064 cur++;
William M. Brack99127052004-05-24 02:52:28 +000010065 } else if (*cur == '+') {
10066 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010067 }
10068 while ((*cur >= '0') && (*cur <= '9')) {
10069 exponent = exponent * 10 + (*cur - '0');
10070 cur++;
10071 }
10072 }
William M. Brack76e95df2003-10-18 16:20:14 +000010073 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +000010074 if (*cur != 0) return(xmlXPathNAN);
10075 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010076 if (is_exponent_negative) exponent = -exponent;
10077 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +000010078 return(ret);
10079}
10080
10081/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010082 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +000010083 * @ctxt: the XPath Parser context
10084 *
10085 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard45490ae2008-07-29 09:13:19 +000010086 * | '.' Digits
Owen Taylor3473f882001-02-23 17:55:21 +000010087 * [31] Digits ::= [0-9]+
10088 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010089 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +000010090 *
10091 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010092static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010093xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10094{
Owen Taylor3473f882001-02-23 17:55:21 +000010095 double ret = 0.0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010096 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010097 int exponent = 0;
10098 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010099#ifdef __GNUC__
10100 unsigned long tmp = 0;
10101 double temp;
10102#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010103
10104 CHECK_ERROR;
10105 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10106 XP_ERROR(XPATH_NUMBER_ERROR);
10107 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010108#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010109 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010110 * tmp/temp is a workaround against a gcc compiler bug
10111 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010112 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010113 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010114 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010115 ret = ret * 10;
10116 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010117 ok = 1;
10118 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +000010119 temp = (double) tmp;
10120 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010121 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010122#else
10123 ret = 0;
10124 while ((CUR >= '0') && (CUR <= '9')) {
10125 ret = ret * 10 + (CUR - '0');
10126 ok = 1;
10127 NEXT;
10128 }
10129#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010130 if (CUR == '.') {
Phil Shaferee32ad32010-11-03 20:53:55 +010010131 int v, frac = 0;
10132 double fraction = 0;
10133
Owen Taylor3473f882001-02-23 17:55:21 +000010134 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010135 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10136 XP_ERROR(XPATH_NUMBER_ERROR);
10137 }
Phil Shaferee32ad32010-11-03 20:53:55 +010010138 while ((CUR >= '0') && (CUR <= '9') && (frac < MAX_FRAC)) {
10139 v = (CUR - '0');
10140 fraction = fraction * 10 + v;
10141 frac = frac + 1;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010142 NEXT;
10143 }
Phil Shaferee32ad32010-11-03 20:53:55 +010010144 fraction /= my_pow10[frac];
10145 ret = ret + fraction;
10146 while ((CUR >= '0') && (CUR <= '9'))
10147 NEXT;
Owen Taylor3473f882001-02-23 17:55:21 +000010148 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010149 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010150 NEXT;
10151 if (CUR == '-') {
10152 is_exponent_negative = 1;
10153 NEXT;
William M. Brack99127052004-05-24 02:52:28 +000010154 } else if (CUR == '+') {
10155 NEXT;
10156 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010157 while ((CUR >= '0') && (CUR <= '9')) {
10158 exponent = exponent * 10 + (CUR - '0');
10159 NEXT;
10160 }
10161 if (is_exponent_negative)
10162 exponent = -exponent;
10163 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +000010164 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010165 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010166 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010167}
10168
10169/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010170 * xmlXPathParseLiteral:
10171 * @ctxt: the XPath Parser context
10172 *
10173 * Parse a Literal
10174 *
10175 * [29] Literal ::= '"' [^"]* '"'
10176 * | "'" [^']* "'"
10177 *
10178 * Returns the value found or NULL in case of error
10179 */
10180static xmlChar *
10181xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10182 const xmlChar *q;
10183 xmlChar *ret = NULL;
10184
10185 if (CUR == '"') {
10186 NEXT;
10187 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010188 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010189 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010190 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010191 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010192 } else {
10193 ret = xmlStrndup(q, CUR_PTR - q);
10194 NEXT;
10195 }
10196 } else if (CUR == '\'') {
10197 NEXT;
10198 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010199 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010200 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010201 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010202 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010203 } else {
10204 ret = xmlStrndup(q, CUR_PTR - q);
10205 NEXT;
10206 }
10207 } else {
Daniel Veillard24505b02005-07-28 23:49:35 +000010208 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010209 }
10210 return(ret);
10211}
10212
10213/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010214 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +000010215 * @ctxt: the XPath Parser context
10216 *
10217 * Parse a Literal and push it on the stack.
10218 *
10219 * [29] Literal ::= '"' [^"]* '"'
10220 * | "'" [^']* "'"
10221 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010222 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +000010223 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010224static void
10225xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010226 const xmlChar *q;
10227 xmlChar *ret = NULL;
10228
10229 if (CUR == '"') {
10230 NEXT;
10231 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010232 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +000010233 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010234 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010235 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10236 } else {
10237 ret = xmlStrndup(q, CUR_PTR - q);
10238 NEXT;
10239 }
10240 } else if (CUR == '\'') {
10241 NEXT;
10242 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010243 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +000010244 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010245 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010246 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10247 } else {
10248 ret = xmlStrndup(q, CUR_PTR - q);
10249 NEXT;
10250 }
10251 } else {
10252 XP_ERROR(XPATH_START_LITERAL_ERROR);
10253 }
10254 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010255 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010256 xmlXPathCacheNewString(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010257 xmlFree(ret);
10258}
10259
10260/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010261 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +000010262 * @ctxt: the XPath Parser context
10263 *
10264 * Parse a VariableReference, evaluate it and push it on the stack.
10265 *
10266 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +000010267 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +000010268 * of any of the types that are possible for the value of an expression,
10269 * and may also be of additional types not specified here.
10270 *
10271 * Early evaluation is possible since:
10272 * The variable bindings [...] used to evaluate a subexpression are
Daniel Veillard45490ae2008-07-29 09:13:19 +000010273 * always the same as those used to evaluate the containing expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010274 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010275 * [36] VariableReference ::= '$' QName
Owen Taylor3473f882001-02-23 17:55:21 +000010276 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010277static void
10278xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010279 xmlChar *name;
10280 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010281
10282 SKIP_BLANKS;
10283 if (CUR != '$') {
10284 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10285 }
10286 NEXT;
10287 name = xmlXPathParseQName(ctxt, &prefix);
10288 if (name == NULL) {
10289 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10290 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010291 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010292 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10293 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010294 SKIP_BLANKS;
Daniel Veillardb3d14912005-09-04 20:47:39 +000010295 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10296 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
10297 }
Owen Taylor3473f882001-02-23 17:55:21 +000010298}
10299
10300/**
10301 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +000010302 * @name: a name string
10303 *
10304 * Is the name given a NodeType one.
10305 *
10306 * [38] NodeType ::= 'comment'
10307 * | 'text'
10308 * | 'processing-instruction'
10309 * | 'node'
10310 *
10311 * Returns 1 if true 0 otherwise
10312 */
10313int
10314xmlXPathIsNodeType(const xmlChar *name) {
10315 if (name == NULL)
10316 return(0);
10317
Daniel Veillard1971ee22002-01-31 20:29:19 +000010318 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +000010319 return(1);
10320 if (xmlStrEqual(name, BAD_CAST "text"))
10321 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010322 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +000010323 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010324 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +000010325 return(1);
10326 return(0);
10327}
10328
10329/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010330 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +000010331 * @ctxt: the XPath Parser context
10332 *
10333 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010334 * [17] Argument ::= Expr
Owen Taylor3473f882001-02-23 17:55:21 +000010335 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010336 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +000010337 * pushed on the stack
10338 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010339static void
10340xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010341 xmlChar *name;
10342 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010343 int nbargs = 0;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010344 int sort = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010345
10346 name = xmlXPathParseQName(ctxt, &prefix);
10347 if (name == NULL) {
Daniel Veillard074f37e2008-09-01 13:38:22 +000010348 xmlFree(prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010349 XP_ERROR(XPATH_EXPR_ERROR);
10350 }
10351 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010352#ifdef DEBUG_EXPR
10353 if (prefix == NULL)
10354 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10355 name);
10356 else
10357 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10358 prefix, name);
10359#endif
10360
Owen Taylor3473f882001-02-23 17:55:21 +000010361 if (CUR != '(') {
10362 XP_ERROR(XPATH_EXPR_ERROR);
10363 }
10364 NEXT;
10365 SKIP_BLANKS;
10366
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010367 /*
10368 * Optimization for count(): we don't need the node-set to be sorted.
10369 */
10370 if ((prefix == NULL) && (name[0] == 'c') &&
10371 xmlStrEqual(name, BAD_CAST "count"))
10372 {
10373 sort = 0;
10374 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010375 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +000010376 if (CUR != ')') {
10377 while (CUR != 0) {
10378 int op1 = ctxt->comp->last;
10379 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010380 xmlXPathCompileExpr(ctxt, sort);
Daniel Veillard074f37e2008-09-01 13:38:22 +000010381 if (ctxt->error != XPATH_EXPRESSION_OK) {
10382 xmlFree(name);
10383 xmlFree(prefix);
10384 return;
10385 }
Daniel Veillard71f9d732003-01-14 16:07:16 +000010386 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10387 nbargs++;
10388 if (CUR == ')') break;
10389 if (CUR != ',') {
10390 XP_ERROR(XPATH_EXPR_ERROR);
10391 }
10392 NEXT;
10393 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010394 }
Owen Taylor3473f882001-02-23 17:55:21 +000010395 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010396 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10397 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010398 NEXT;
10399 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010400}
10401
10402/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010403 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010404 * @ctxt: the XPath Parser context
10405 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010406 * [15] PrimaryExpr ::= VariableReference
Owen Taylor3473f882001-02-23 17:55:21 +000010407 * | '(' Expr ')'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010408 * | Literal
10409 * | Number
10410 * | FunctionCall
Owen Taylor3473f882001-02-23 17:55:21 +000010411 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010412 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010413 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010414static void
10415xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010416 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010417 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010418 else if (CUR == '(') {
10419 NEXT;
10420 SKIP_BLANKS;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010421 xmlXPathCompileExpr(ctxt, 1);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010422 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000010423 if (CUR != ')') {
10424 XP_ERROR(XPATH_EXPR_ERROR);
10425 }
10426 NEXT;
10427 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010428 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010429 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010430 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010431 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010432 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010433 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010434 }
10435 SKIP_BLANKS;
10436}
10437
10438/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010439 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010440 * @ctxt: the XPath Parser context
10441 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010442 * [20] FilterExpr ::= PrimaryExpr
10443 * | FilterExpr Predicate
Owen Taylor3473f882001-02-23 17:55:21 +000010444 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010445 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010446 * Square brackets are used to filter expressions in the same way that
10447 * they are used in location paths. It is an error if the expression to
10448 * be filtered does not evaluate to a node-set. The context node list
10449 * used for evaluating the expression in square brackets is the node-set
10450 * to be filtered listed in document order.
10451 */
10452
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010453static void
10454xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10455 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010456 CHECK_ERROR;
10457 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010458
Owen Taylor3473f882001-02-23 17:55:21 +000010459 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010460 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +000010461 SKIP_BLANKS;
10462 }
10463
Daniel Veillard45490ae2008-07-29 09:13:19 +000010464
Owen Taylor3473f882001-02-23 17:55:21 +000010465}
10466
10467/**
10468 * xmlXPathScanName:
10469 * @ctxt: the XPath Parser context
10470 *
10471 * Trickery: parse an XML name but without consuming the input flow
10472 * Needed to avoid insanity in the parser state.
10473 *
10474 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10475 * CombiningChar | Extender
10476 *
10477 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10478 *
10479 * [6] Names ::= Name (S Name)*
10480 *
10481 * Returns the Name parsed or NULL
10482 */
10483
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010484static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +000010485xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +000010486 int len = 0, l;
10487 int c;
Daniel Veillard03226812004-11-01 14:55:21 +000010488 const xmlChar *cur;
10489 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +000010490
Daniel Veillard03226812004-11-01 14:55:21 +000010491 cur = ctxt->cur;
10492
10493 c = CUR_CHAR(l);
10494 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10495 (!IS_LETTER(c) && (c != '_') &&
10496 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010497 return(NULL);
10498 }
10499
Daniel Veillard03226812004-11-01 14:55:21 +000010500 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10501 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10502 (c == '.') || (c == '-') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000010503 (c == '_') || (c == ':') ||
Daniel Veillard03226812004-11-01 14:55:21 +000010504 (IS_COMBINING(c)) ||
10505 (IS_EXTENDER(c)))) {
10506 len += l;
10507 NEXTL(l);
10508 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +000010509 }
Daniel Veillard03226812004-11-01 14:55:21 +000010510 ret = xmlStrndup(cur, ctxt->cur - cur);
10511 ctxt->cur = cur;
10512 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +000010513}
10514
10515/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010516 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010517 * @ctxt: the XPath Parser context
10518 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010519 * [19] PathExpr ::= LocationPath
10520 * | FilterExpr
10521 * | FilterExpr '/' RelativeLocationPath
10522 * | FilterExpr '//' RelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000010523 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010524 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010525 * The / operator and // operators combine an arbitrary expression
10526 * and a relative location path. It is an error if the expression
10527 * does not evaluate to a node-set.
10528 * The / operator does composition in the same way as when / is
10529 * used in a location path. As in location paths, // is short for
10530 * /descendant-or-self::node()/.
10531 */
10532
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010533static void
10534xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010535 int lc = 1; /* Should we branch to LocationPath ? */
10536 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10537
10538 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010539 if ((CUR == '$') || (CUR == '(') ||
10540 (IS_ASCII_DIGIT(CUR)) ||
William M. Brackd1757ab2004-10-02 22:07:48 +000010541 (CUR == '\'') || (CUR == '"') ||
10542 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010543 lc = 0;
10544 } else if (CUR == '*') {
10545 /* relative or absolute location path */
10546 lc = 1;
10547 } else if (CUR == '/') {
10548 /* relative or absolute location path */
10549 lc = 1;
10550 } else if (CUR == '@') {
10551 /* relative abbreviated attribute location path */
10552 lc = 1;
10553 } else if (CUR == '.') {
10554 /* relative abbreviated attribute location path */
10555 lc = 1;
10556 } else {
10557 /*
10558 * Problem is finding if we have a name here whether it's:
10559 * - a nodetype
10560 * - a function call in which case it's followed by '('
10561 * - an axis in which case it's followed by ':'
10562 * - a element name
10563 * We do an a priori analysis here rather than having to
10564 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +000010565 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +000010566 * read/write/debug.
10567 */
10568 SKIP_BLANKS;
10569 name = xmlXPathScanName(ctxt);
10570 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10571#ifdef DEBUG_STEP
10572 xmlGenericError(xmlGenericErrorContext,
10573 "PathExpr: Axis\n");
10574#endif
10575 lc = 1;
10576 xmlFree(name);
10577 } else if (name != NULL) {
10578 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +000010579
Daniel Veillard45490ae2008-07-29 09:13:19 +000010580
Owen Taylor3473f882001-02-23 17:55:21 +000010581 while (NXT(len) != 0) {
10582 if (NXT(len) == '/') {
10583 /* element name */
10584#ifdef DEBUG_STEP
10585 xmlGenericError(xmlGenericErrorContext,
10586 "PathExpr: AbbrRelLocation\n");
10587#endif
10588 lc = 1;
10589 break;
William M. Brack76e95df2003-10-18 16:20:14 +000010590 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +000010591 /* ignore blanks */
10592 ;
Owen Taylor3473f882001-02-23 17:55:21 +000010593 } else if (NXT(len) == ':') {
10594#ifdef DEBUG_STEP
10595 xmlGenericError(xmlGenericErrorContext,
10596 "PathExpr: AbbrRelLocation\n");
10597#endif
10598 lc = 1;
10599 break;
10600 } else if ((NXT(len) == '(')) {
10601 /* Note Type or Function */
10602 if (xmlXPathIsNodeType(name)) {
10603#ifdef DEBUG_STEP
10604 xmlGenericError(xmlGenericErrorContext,
10605 "PathExpr: Type search\n");
10606#endif
10607 lc = 1;
10608 } else {
10609#ifdef DEBUG_STEP
10610 xmlGenericError(xmlGenericErrorContext,
10611 "PathExpr: function call\n");
10612#endif
10613 lc = 0;
10614 }
10615 break;
10616 } else if ((NXT(len) == '[')) {
10617 /* element name */
10618#ifdef DEBUG_STEP
10619 xmlGenericError(xmlGenericErrorContext,
10620 "PathExpr: AbbrRelLocation\n");
10621#endif
10622 lc = 1;
10623 break;
10624 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10625 (NXT(len) == '=')) {
10626 lc = 1;
10627 break;
10628 } else {
10629 lc = 1;
10630 break;
10631 }
10632 len++;
10633 }
10634 if (NXT(len) == 0) {
10635#ifdef DEBUG_STEP
10636 xmlGenericError(xmlGenericErrorContext,
10637 "PathExpr: AbbrRelLocation\n");
10638#endif
10639 /* element name */
10640 lc = 1;
10641 }
10642 xmlFree(name);
10643 } else {
William M. Brack08171912003-12-29 02:52:11 +000010644 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +000010645 XP_ERROR(XPATH_EXPR_ERROR);
10646 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000010647 }
Owen Taylor3473f882001-02-23 17:55:21 +000010648
10649 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010650 if (CUR == '/') {
10651 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10652 } else {
10653 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010654 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010655 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010656 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010657 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010658 CHECK_ERROR;
10659 if ((CUR == '/') && (NXT(1) == '/')) {
10660 SKIP(2);
10661 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010662
10663 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10664 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10665 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10666
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010667 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010668 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010669 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010670 }
10671 }
10672 SKIP_BLANKS;
10673}
10674
10675/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010676 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010677 * @ctxt: the XPath Parser context
10678 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010679 * [18] UnionExpr ::= PathExpr
10680 * | UnionExpr '|' PathExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010681 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010682 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010683 */
10684
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010685static void
10686xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10687 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010688 CHECK_ERROR;
10689 SKIP_BLANKS;
10690 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010691 int op1 = ctxt->comp->last;
10692 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010693
10694 NEXT;
10695 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010696 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010697
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010698 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10699
Owen Taylor3473f882001-02-23 17:55:21 +000010700 SKIP_BLANKS;
10701 }
Owen Taylor3473f882001-02-23 17:55:21 +000010702}
10703
10704/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010705 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010706 * @ctxt: the XPath Parser context
10707 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010708 * [27] UnaryExpr ::= UnionExpr
10709 * | '-' UnaryExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010710 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010711 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010712 */
10713
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010714static void
10715xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010716 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010717 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010718
10719 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +000010720 while (CUR == '-') {
10721 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010722 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010723 NEXT;
10724 SKIP_BLANKS;
10725 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010726
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010727 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010728 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010729 if (found) {
10730 if (minus)
10731 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10732 else
10733 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010734 }
10735}
10736
10737/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010738 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010739 * @ctxt: the XPath Parser context
10740 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010741 * [26] MultiplicativeExpr ::= UnaryExpr
10742 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10743 * | MultiplicativeExpr 'div' UnaryExpr
10744 * | MultiplicativeExpr 'mod' UnaryExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010745 * [34] MultiplyOperator ::= '*'
10746 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010747 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010748 */
10749
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010750static void
10751xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10752 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010753 CHECK_ERROR;
10754 SKIP_BLANKS;
Daniel Veillard45490ae2008-07-29 09:13:19 +000010755 while ((CUR == '*') ||
Owen Taylor3473f882001-02-23 17:55:21 +000010756 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10757 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10758 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010759 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010760
10761 if (CUR == '*') {
10762 op = 0;
10763 NEXT;
10764 } else if (CUR == 'd') {
10765 op = 1;
10766 SKIP(3);
10767 } else if (CUR == 'm') {
10768 op = 2;
10769 SKIP(3);
10770 }
10771 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010772 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010773 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010774 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010775 SKIP_BLANKS;
10776 }
10777}
10778
10779/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010780 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010781 * @ctxt: the XPath Parser context
10782 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010783 * [25] AdditiveExpr ::= MultiplicativeExpr
10784 * | AdditiveExpr '+' MultiplicativeExpr
10785 * | AdditiveExpr '-' MultiplicativeExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010786 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010787 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010788 */
10789
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010790static void
10791xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010792
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010793 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010794 CHECK_ERROR;
10795 SKIP_BLANKS;
10796 while ((CUR == '+') || (CUR == '-')) {
10797 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010798 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010799
10800 if (CUR == '+') plus = 1;
10801 else plus = 0;
10802 NEXT;
10803 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010804 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010805 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010806 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010807 SKIP_BLANKS;
10808 }
10809}
10810
10811/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010812 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010813 * @ctxt: the XPath Parser context
10814 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010815 * [24] RelationalExpr ::= AdditiveExpr
10816 * | RelationalExpr '<' AdditiveExpr
10817 * | RelationalExpr '>' AdditiveExpr
10818 * | RelationalExpr '<=' AdditiveExpr
10819 * | RelationalExpr '>=' AdditiveExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010820 *
10821 * A <= B > C is allowed ? Answer from James, yes with
10822 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10823 * which is basically what got implemented.
10824 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010825 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +000010826 * on the stack
10827 */
10828
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010829static void
10830xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10831 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010832 CHECK_ERROR;
10833 SKIP_BLANKS;
10834 while ((CUR == '<') ||
10835 (CUR == '>') ||
10836 ((CUR == '<') && (NXT(1) == '=')) ||
10837 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010838 int inf, strict;
10839 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010840
10841 if (CUR == '<') inf = 1;
10842 else inf = 0;
10843 if (NXT(1) == '=') strict = 0;
10844 else strict = 1;
10845 NEXT;
10846 if (!strict) NEXT;
10847 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010848 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010849 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010850 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +000010851 SKIP_BLANKS;
10852 }
10853}
10854
10855/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010856 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010857 * @ctxt: the XPath Parser context
10858 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010859 * [23] EqualityExpr ::= RelationalExpr
10860 * | EqualityExpr '=' RelationalExpr
10861 * | EqualityExpr '!=' RelationalExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010862 *
10863 * A != B != C is allowed ? Answer from James, yes with
10864 * (RelationalExpr = RelationalExpr) = RelationalExpr
10865 * (RelationalExpr != RelationalExpr) != RelationalExpr
10866 * which is basically what got implemented.
10867 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010868 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010869 *
10870 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010871static void
10872xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10873 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010874 CHECK_ERROR;
10875 SKIP_BLANKS;
10876 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010877 int eq;
10878 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010879
10880 if (CUR == '=') eq = 1;
10881 else eq = 0;
10882 NEXT;
10883 if (!eq) NEXT;
10884 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010885 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010886 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010887 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010888 SKIP_BLANKS;
10889 }
10890}
10891
10892/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010893 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010894 * @ctxt: the XPath Parser context
10895 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010896 * [22] AndExpr ::= EqualityExpr
10897 * | AndExpr 'and' EqualityExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010898 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010899 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010900 *
10901 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010902static void
10903xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10904 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010905 CHECK_ERROR;
10906 SKIP_BLANKS;
10907 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010908 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010909 SKIP(3);
10910 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010911 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010912 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010913 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010914 SKIP_BLANKS;
10915 }
10916}
10917
10918/**
Daniel Veillard591b4be2003-02-09 23:33:36 +000010919 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010920 * @ctxt: the XPath Parser context
10921 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000010922 * [14] Expr ::= OrExpr
10923 * [21] OrExpr ::= AndExpr
10924 * | OrExpr 'or' AndExpr
Owen Taylor3473f882001-02-23 17:55:21 +000010925 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010926 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +000010927 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010928static void
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010929xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010930 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010931 CHECK_ERROR;
10932 SKIP_BLANKS;
10933 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010934 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010935 SKIP(2);
10936 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010937 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010938 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010939 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010940 SKIP_BLANKS;
10941 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010942 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010943 /* more ops could be optimized too */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010944 /*
10945 * This is the main place to eliminate sorting for
10946 * operations which don't require a sorted node-set.
10947 * E.g. count().
10948 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010949 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10950 }
Owen Taylor3473f882001-02-23 17:55:21 +000010951}
10952
10953/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010954 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +000010955 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010956 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +000010957 *
10958 * [8] Predicate ::= '[' PredicateExpr ']'
Daniel Veillard45490ae2008-07-29 09:13:19 +000010959 * [9] PredicateExpr ::= Expr
Owen Taylor3473f882001-02-23 17:55:21 +000010960 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010961 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +000010962 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010963static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010964xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010965 int op1 = ctxt->comp->last;
10966
10967 SKIP_BLANKS;
10968 if (CUR != '[') {
10969 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10970 }
10971 NEXT;
10972 SKIP_BLANKS;
10973
10974 ctxt->comp->last = -1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000010975 /*
10976 * This call to xmlXPathCompileExpr() will deactivate sorting
10977 * of the predicate result.
10978 * TODO: Sorting is still activated for filters, since I'm not
10979 * sure if needed. Normally sorting should not be needed, since
10980 * a filter can only diminish the number of items in a sequence,
10981 * but won't change its order; so if the initial sequence is sorted,
10982 * subsequent sorting is not needed.
10983 */
10984 if (! filter)
10985 xmlXPathCompileExpr(ctxt, 0);
10986 else
10987 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010988 CHECK_ERROR;
10989
10990 if (CUR != ']') {
10991 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10992 }
10993
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010994 if (filter)
10995 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10996 else
10997 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010998
10999 NEXT;
11000 SKIP_BLANKS;
11001}
11002
11003/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011004 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +000011005 * @ctxt: the XPath Parser context
11006 * @test: pointer to a xmlXPathTestVal
11007 * @type: pointer to a xmlXPathTypeVal
11008 * @prefix: placeholder for a possible name prefix
11009 *
11010 * [7] NodeTest ::= NameTest
11011 * | NodeType '(' ')'
11012 * | 'processing-instruction' '(' Literal ')'
11013 *
11014 * [37] NameTest ::= '*'
11015 * | NCName ':' '*'
11016 * | QName
11017 * [38] NodeType ::= 'comment'
11018 * | 'text'
11019 * | 'processing-instruction'
11020 * | 'node'
11021 *
William M. Brack08171912003-12-29 02:52:11 +000011022 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +000011023 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011024static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011025xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11026 xmlXPathTypeVal *type, const xmlChar **prefix,
11027 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +000011028 int blanks;
11029
11030 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11031 STRANGE;
11032 return(NULL);
11033 }
William M. Brack78637da2003-07-31 14:47:38 +000011034 *type = (xmlXPathTypeVal) 0;
11035 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011036 *prefix = NULL;
11037 SKIP_BLANKS;
11038
11039 if ((name == NULL) && (CUR == '*')) {
11040 /*
11041 * All elements
11042 */
11043 NEXT;
11044 *test = NODE_TEST_ALL;
11045 return(NULL);
11046 }
11047
11048 if (name == NULL)
11049 name = xmlXPathParseNCName(ctxt);
11050 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011051 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011052 }
11053
William M. Brack76e95df2003-10-18 16:20:14 +000011054 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +000011055 SKIP_BLANKS;
11056 if (CUR == '(') {
11057 NEXT;
11058 /*
11059 * NodeType or PI search
11060 */
11061 if (xmlStrEqual(name, BAD_CAST "comment"))
11062 *type = NODE_TYPE_COMMENT;
11063 else if (xmlStrEqual(name, BAD_CAST "node"))
11064 *type = NODE_TYPE_NODE;
11065 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11066 *type = NODE_TYPE_PI;
11067 else if (xmlStrEqual(name, BAD_CAST "text"))
11068 *type = NODE_TYPE_TEXT;
11069 else {
11070 if (name != NULL)
11071 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000011072 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011073 }
11074
11075 *test = NODE_TEST_TYPE;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011076
Owen Taylor3473f882001-02-23 17:55:21 +000011077 SKIP_BLANKS;
11078 if (*type == NODE_TYPE_PI) {
11079 /*
11080 * Specific case: search a PI by name.
11081 */
Owen Taylor3473f882001-02-23 17:55:21 +000011082 if (name != NULL)
11083 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +000011084 name = NULL;
11085 if (CUR != ')') {
11086 name = xmlXPathParseLiteral(ctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000011087 CHECK_ERROR NULL;
Daniel Veillarded23b7d2002-05-27 12:16:02 +000011088 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +000011089 SKIP_BLANKS;
11090 }
Owen Taylor3473f882001-02-23 17:55:21 +000011091 }
11092 if (CUR != ')') {
11093 if (name != NULL)
11094 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000011095 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011096 }
11097 NEXT;
11098 return(name);
11099 }
11100 *test = NODE_TEST_NAME;
11101 if ((!blanks) && (CUR == ':')) {
11102 NEXT;
11103
11104 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011105 * Since currently the parser context don't have a
11106 * namespace list associated:
11107 * The namespace name for this prefix can be computed
11108 * only at evaluation time. The compilation is done
11109 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +000011110 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011111#if 0
Owen Taylor3473f882001-02-23 17:55:21 +000011112 *prefix = xmlXPathNsLookup(ctxt->context, name);
11113 if (name != NULL)
11114 xmlFree(name);
11115 if (*prefix == NULL) {
11116 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11117 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011118#else
11119 *prefix = name;
11120#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011121
11122 if (CUR == '*') {
11123 /*
11124 * All elements
11125 */
11126 NEXT;
11127 *test = NODE_TEST_ALL;
11128 return(NULL);
11129 }
11130
11131 name = xmlXPathParseNCName(ctxt);
11132 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011133 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011134 }
11135 }
11136 return(name);
11137}
11138
11139/**
11140 * xmlXPathIsAxisName:
11141 * @name: a preparsed name token
11142 *
11143 * [6] AxisName ::= 'ancestor'
11144 * | 'ancestor-or-self'
11145 * | 'attribute'
11146 * | 'child'
11147 * | 'descendant'
11148 * | 'descendant-or-self'
11149 * | 'following'
11150 * | 'following-sibling'
11151 * | 'namespace'
11152 * | 'parent'
11153 * | 'preceding'
11154 * | 'preceding-sibling'
11155 * | 'self'
11156 *
11157 * Returns the axis or 0
11158 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011159static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +000011160xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +000011161 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011162 switch (name[0]) {
11163 case 'a':
11164 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11165 ret = AXIS_ANCESTOR;
11166 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11167 ret = AXIS_ANCESTOR_OR_SELF;
11168 if (xmlStrEqual(name, BAD_CAST "attribute"))
11169 ret = AXIS_ATTRIBUTE;
11170 break;
11171 case 'c':
11172 if (xmlStrEqual(name, BAD_CAST "child"))
11173 ret = AXIS_CHILD;
11174 break;
11175 case 'd':
11176 if (xmlStrEqual(name, BAD_CAST "descendant"))
11177 ret = AXIS_DESCENDANT;
11178 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11179 ret = AXIS_DESCENDANT_OR_SELF;
11180 break;
11181 case 'f':
11182 if (xmlStrEqual(name, BAD_CAST "following"))
11183 ret = AXIS_FOLLOWING;
11184 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11185 ret = AXIS_FOLLOWING_SIBLING;
11186 break;
11187 case 'n':
11188 if (xmlStrEqual(name, BAD_CAST "namespace"))
11189 ret = AXIS_NAMESPACE;
11190 break;
11191 case 'p':
11192 if (xmlStrEqual(name, BAD_CAST "parent"))
11193 ret = AXIS_PARENT;
11194 if (xmlStrEqual(name, BAD_CAST "preceding"))
11195 ret = AXIS_PRECEDING;
11196 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11197 ret = AXIS_PRECEDING_SIBLING;
11198 break;
11199 case 's':
11200 if (xmlStrEqual(name, BAD_CAST "self"))
11201 ret = AXIS_SELF;
11202 break;
11203 }
11204 return(ret);
11205}
11206
11207/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011208 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +000011209 * @ctxt: the XPath Parser context
11210 *
11211 * [4] Step ::= AxisSpecifier NodeTest Predicate*
Daniel Veillard45490ae2008-07-29 09:13:19 +000011212 * | AbbreviatedStep
Owen Taylor3473f882001-02-23 17:55:21 +000011213 *
11214 * [12] AbbreviatedStep ::= '.' | '..'
11215 *
11216 * [5] AxisSpecifier ::= AxisName '::'
11217 * | AbbreviatedAxisSpecifier
11218 *
11219 * [13] AbbreviatedAxisSpecifier ::= '@'?
11220 *
11221 * Modified for XPtr range support as:
11222 *
11223 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11224 * | AbbreviatedStep
11225 * | 'range-to' '(' Expr ')' Predicate*
11226 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011227 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +000011228 * A location step of . is short for self::node(). This is
11229 * particularly useful in conjunction with //. For example, the
11230 * location path .//para is short for
11231 * self::node()/descendant-or-self::node()/child::para
11232 * and so will select all para descendant elements of the context
11233 * node.
11234 * Similarly, a location step of .. is short for parent::node().
11235 * For example, ../title is short for parent::node()/child::title
11236 * and so will select the title children of the parent of the context
11237 * node.
11238 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011239static void
11240xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011241#ifdef LIBXML_XPTR_ENABLED
11242 int rangeto = 0;
11243 int op2 = -1;
11244#endif
11245
Owen Taylor3473f882001-02-23 17:55:21 +000011246 SKIP_BLANKS;
11247 if ((CUR == '.') && (NXT(1) == '.')) {
11248 SKIP(2);
11249 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011250 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11251 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011252 } else if (CUR == '.') {
11253 NEXT;
11254 SKIP_BLANKS;
11255 } else {
11256 xmlChar *name = NULL;
11257 const xmlChar *prefix = NULL;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011258 xmlXPathTestVal test = (xmlXPathTestVal) 0;
William M. Brack78637da2003-07-31 14:47:38 +000011259 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011260 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011261 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +000011262
11263 /*
11264 * The modification needed for XPointer change to the production
11265 */
11266#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011267 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +000011268 name = xmlXPathParseNCName(ctxt);
11269 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011270 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011271 xmlFree(name);
11272 SKIP_BLANKS;
11273 if (CUR != '(') {
11274 XP_ERROR(XPATH_EXPR_ERROR);
11275 }
11276 NEXT;
11277 SKIP_BLANKS;
11278
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011279 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011280 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +000011281 CHECK_ERROR;
11282
11283 SKIP_BLANKS;
11284 if (CUR != ')') {
11285 XP_ERROR(XPATH_EXPR_ERROR);
11286 }
11287 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011288 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000011289 goto eval_predicates;
11290 }
11291 }
11292#endif
Daniel Veillard2156a562001-04-28 12:24:34 +000011293 if (CUR == '*') {
11294 axis = AXIS_CHILD;
11295 } else {
11296 if (name == NULL)
11297 name = xmlXPathParseNCName(ctxt);
11298 if (name != NULL) {
11299 axis = xmlXPathIsAxisName(name);
11300 if (axis != 0) {
11301 SKIP_BLANKS;
11302 if ((CUR == ':') && (NXT(1) == ':')) {
11303 SKIP(2);
11304 xmlFree(name);
11305 name = NULL;
11306 } else {
11307 /* an element name can conflict with an axis one :-\ */
11308 axis = AXIS_CHILD;
11309 }
Owen Taylor3473f882001-02-23 17:55:21 +000011310 } else {
Owen Taylor3473f882001-02-23 17:55:21 +000011311 axis = AXIS_CHILD;
11312 }
Daniel Veillard2156a562001-04-28 12:24:34 +000011313 } else if (CUR == '@') {
11314 NEXT;
11315 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +000011316 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +000011317 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +000011318 }
Owen Taylor3473f882001-02-23 17:55:21 +000011319 }
11320
Daniel Veillard2f3523f2010-10-15 18:30:29 +020011321 if (ctxt->error != XPATH_EXPRESSION_OK) {
11322 xmlFree(name);
11323 return;
11324 }
Owen Taylor3473f882001-02-23 17:55:21 +000011325
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011326 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +000011327 if (test == 0)
11328 return;
11329
Daniel Veillarded6c5492005-07-23 15:00:22 +000011330 if ((prefix != NULL) && (ctxt->context != NULL) &&
11331 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11332 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11333 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11334 }
11335 }
Owen Taylor3473f882001-02-23 17:55:21 +000011336#ifdef DEBUG_STEP
11337 xmlGenericError(xmlGenericErrorContext,
11338 "Basis : computing new set\n");
11339#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011340
Owen Taylor3473f882001-02-23 17:55:21 +000011341#ifdef DEBUG_STEP
11342 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011343 if (ctxt->value == NULL)
11344 xmlGenericError(xmlGenericErrorContext, "no value\n");
11345 else if (ctxt->value->nodesetval == NULL)
11346 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11347 else
11348 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011349#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011350
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011351#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +000011352eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011353#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011354 op1 = ctxt->comp->last;
11355 ctxt->comp->last = -1;
11356
Owen Taylor3473f882001-02-23 17:55:21 +000011357 SKIP_BLANKS;
11358 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011359 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011360 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011361
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011362#ifdef LIBXML_XPTR_ENABLED
11363 if (rangeto) {
11364 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11365 } else
11366#endif
11367 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11368 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011369
Owen Taylor3473f882001-02-23 17:55:21 +000011370 }
11371#ifdef DEBUG_STEP
11372 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011373 if (ctxt->value == NULL)
11374 xmlGenericError(xmlGenericErrorContext, "no value\n");
11375 else if (ctxt->value->nodesetval == NULL)
11376 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11377 else
11378 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11379 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011380#endif
11381}
11382
11383/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011384 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011385 * @ctxt: the XPath Parser context
11386 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011387 * [3] RelativeLocationPath ::= Step
11388 * | RelativeLocationPath '/' Step
11389 * | AbbreviatedRelativeLocationPath
11390 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
Owen Taylor3473f882001-02-23 17:55:21 +000011391 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011392 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +000011393 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011394static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011395xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011396(xmlXPathParserContextPtr ctxt) {
11397 SKIP_BLANKS;
11398 if ((CUR == '/') && (NXT(1) == '/')) {
11399 SKIP(2);
11400 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011401 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11402 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011403 } else if (CUR == '/') {
11404 NEXT;
11405 SKIP_BLANKS;
11406 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011407 xmlXPathCompStep(ctxt);
Martin729601f2009-10-12 22:42:26 +020011408 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000011409 SKIP_BLANKS;
11410 while (CUR == '/') {
11411 if ((CUR == '/') && (NXT(1) == '/')) {
11412 SKIP(2);
11413 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011414 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +000011415 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011416 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011417 } else if (CUR == '/') {
11418 NEXT;
11419 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011420 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011421 }
11422 SKIP_BLANKS;
11423 }
11424}
11425
11426/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011427 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011428 * @ctxt: the XPath Parser context
11429 *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011430 * [1] LocationPath ::= RelativeLocationPath
11431 * | AbsoluteLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011432 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
Daniel Veillard45490ae2008-07-29 09:13:19 +000011433 * | AbbreviatedAbsoluteLocationPath
11434 * [10] AbbreviatedAbsoluteLocationPath ::=
11435 * '//' RelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011436 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011437 * Compile a location path
11438 *
Owen Taylor3473f882001-02-23 17:55:21 +000011439 * // is short for /descendant-or-self::node()/. For example,
11440 * //para is short for /descendant-or-self::node()/child::para and
11441 * so will select any para element in the document (even a para element
11442 * that is a document element will be selected by //para since the
11443 * document element node is a child of the root node); div//para is
11444 * short for div/descendant-or-self::node()/child::para and so will
11445 * select all para descendants of div children.
11446 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011447static void
11448xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000011449 SKIP_BLANKS;
11450 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011451 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011452 } else {
11453 while (CUR == '/') {
11454 if ((CUR == '/') && (NXT(1) == '/')) {
11455 SKIP(2);
11456 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011457 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11458 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011459 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011460 } else if (CUR == '/') {
11461 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +000011462 SKIP_BLANKS;
11463 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +000011464 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +000011465 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011466 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011467 }
Martin729601f2009-10-12 22:42:26 +020011468 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000011469 }
11470 }
11471}
11472
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011473/************************************************************************
11474 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +000011475 * XPath precompiled expression evaluation *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011476 * *
11477 ************************************************************************/
11478
Daniel Veillardf06307e2001-07-03 10:35:50 +000011479static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011480xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11481
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011482#ifdef DEBUG_STEP
11483static void
Daniel Veillard074f37e2008-09-01 13:38:22 +000011484xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011485 int nbNodes)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011486{
Daniel Veillardf06307e2001-07-03 10:35:50 +000011487 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillard074f37e2008-09-01 13:38:22 +000011488 switch (op->value) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011489 case AXIS_ANCESTOR:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011490 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011491 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011492 case AXIS_ANCESTOR_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011493 xmlGenericError(xmlGenericErrorContext,
11494 "axis 'ancestors-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011495 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011496 case AXIS_ATTRIBUTE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011497 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011498 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011499 case AXIS_CHILD:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011500 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011501 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011502 case AXIS_DESCENDANT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011503 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011504 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011505 case AXIS_DESCENDANT_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011506 xmlGenericError(xmlGenericErrorContext,
11507 "axis 'descendant-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011508 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011509 case AXIS_FOLLOWING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011510 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011511 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011512 case AXIS_FOLLOWING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011513 xmlGenericError(xmlGenericErrorContext,
11514 "axis 'following-siblings' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011515 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011516 case AXIS_NAMESPACE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011517 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011518 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011519 case AXIS_PARENT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011520 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011521 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011522 case AXIS_PRECEDING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011523 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011524 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011525 case AXIS_PRECEDING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011526 xmlGenericError(xmlGenericErrorContext,
11527 "axis 'preceding-sibling' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011528 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011529 case AXIS_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011530 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011531 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011532 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011533 xmlGenericError(xmlGenericErrorContext,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011534 " context contains %d nodes\n", nbNodes);
Daniel Veillard074f37e2008-09-01 13:38:22 +000011535 switch (op->value2) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011536 case NODE_TEST_NONE:
11537 xmlGenericError(xmlGenericErrorContext,
11538 " searching for none !!!\n");
11539 break;
11540 case NODE_TEST_TYPE:
11541 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011542 " searching for type %d\n", op->value3);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011543 break;
11544 case NODE_TEST_PI:
11545 xmlGenericError(xmlGenericErrorContext,
11546 " searching for PI !!!\n");
11547 break;
11548 case NODE_TEST_ALL:
11549 xmlGenericError(xmlGenericErrorContext,
11550 " searching for *\n");
11551 break;
11552 case NODE_TEST_NS:
11553 xmlGenericError(xmlGenericErrorContext,
11554 " searching for namespace %s\n",
Daniel Veillard074f37e2008-09-01 13:38:22 +000011555 op->value5);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011556 break;
11557 case NODE_TEST_NAME:
11558 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011559 " searching for name %s\n", op->value5);
11560 if (op->value4)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011561 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard074f37e2008-09-01 13:38:22 +000011562 " with namespace %s\n", op->value4);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011563 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011564 }
11565 xmlGenericError(xmlGenericErrorContext, "Testing : ");
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011566}
11567#endif /* DEBUG_STEP */
11568
11569static int
11570xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11571 xmlXPathStepOpPtr op,
11572 xmlNodeSetPtr set,
11573 int contextSize,
11574 int hasNsNodes)
11575{
11576 if (op->ch1 != -1) {
11577 xmlXPathCompExprPtr comp = ctxt->comp;
11578 /*
11579 * Process inner predicates first.
11580 */
11581 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11582 /*
11583 * TODO: raise an internal error.
11584 */
11585 }
11586 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11587 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11588 CHECK_ERROR0;
11589 if (contextSize <= 0)
11590 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011591 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011592 if (op->ch2 != -1) {
11593 xmlXPathContextPtr xpctxt = ctxt->context;
11594 xmlNodePtr contextNode, oldContextNode;
11595 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011596 int i, res, contextPos = 0, newContextSize;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011597 xmlXPathStepOpPtr exprOp;
11598 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11599
11600#ifdef LIBXML_XPTR_ENABLED
11601 /*
11602 * URGENT TODO: Check the following:
11603 * We don't expect location sets if evaluating prediates, right?
11604 * Only filters should expect location sets, right?
11605 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011606#endif
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011607 /*
11608 * SPEC XPath 1.0:
11609 * "For each node in the node-set to be filtered, the
11610 * PredicateExpr is evaluated with that node as the
11611 * context node, with the number of nodes in the
11612 * node-set as the context size, and with the proximity
11613 * position of the node in the node-set with respect to
11614 * the axis as the context position;"
11615 * @oldset is the node-set" to be filtered.
11616 *
11617 * SPEC XPath 1.0:
11618 * "only predicates change the context position and
11619 * context size (see [2.4 Predicates])."
11620 * Example:
11621 * node-set context pos
11622 * nA 1
11623 * nB 2
11624 * nC 3
11625 * After applying predicate [position() > 1] :
11626 * node-set context pos
11627 * nB 1
11628 * nC 2
11629 */
11630 oldContextNode = xpctxt->node;
11631 oldContextDoc = xpctxt->doc;
11632 /*
11633 * Get the expression of this predicate.
11634 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000011635 exprOp = &ctxt->comp->steps[op->ch2];
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011636 newContextSize = 0;
11637 for (i = 0; i < set->nodeNr; i++) {
11638 if (set->nodeTab[i] == NULL)
11639 continue;
11640
11641 contextNode = set->nodeTab[i];
11642 xpctxt->node = contextNode;
11643 xpctxt->contextSize = contextSize;
11644 xpctxt->proximityPosition = ++contextPos;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011645
11646 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011647 * Also set the xpath document in case things like
11648 * key() are evaluated in the predicate.
11649 */
11650 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11651 (contextNode->doc != NULL))
11652 xpctxt->doc = contextNode->doc;
11653 /*
11654 * Evaluate the predicate expression with 1 context node
11655 * at a time; this node is packaged into a node set; this
11656 * node set is handed over to the evaluation mechanism.
11657 */
11658 if (contextObj == NULL)
11659 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11660 else
11661 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11662 contextNode);
11663
11664 valuePush(ctxt, contextObj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011665
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011666 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011667
William M. Brack0bcec062007-02-14 02:15:19 +000011668 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11669 xmlXPathNodeSetClear(set, hasNsNodes);
11670 newContextSize = 0;
11671 goto evaluation_exit;
11672 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011673
11674 if (res != 0) {
11675 newContextSize++;
11676 } else {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011677 /*
11678 * Remove the entry from the initial node set.
11679 */
11680 set->nodeTab[i] = NULL;
11681 if (contextNode->type == XML_NAMESPACE_DECL)
11682 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011683 }
11684 if (ctxt->value == contextObj) {
11685 /*
11686 * Don't free the temporary XPath object holding the
11687 * context node, in order to avoid massive recreation
11688 * inside this loop.
11689 */
11690 valuePop(ctxt);
11691 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11692 } else {
11693 /*
11694 * TODO: The object was lost in the evaluation machinery.
11695 * Can this happen? Maybe in internal-error cases.
11696 */
11697 contextObj = NULL;
11698 }
11699 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011700
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011701 if (contextObj != NULL) {
11702 if (ctxt->value == contextObj)
11703 valuePop(ctxt);
11704 xmlXPathReleaseObject(xpctxt, contextObj);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011705 }
William M. Brack0bcec062007-02-14 02:15:19 +000011706evaluation_exit:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011707 if (exprRes != NULL)
11708 xmlXPathReleaseObject(ctxt->context, exprRes);
11709 /*
11710 * Reset/invalidate the context.
11711 */
11712 xpctxt->node = oldContextNode;
11713 xpctxt->doc = oldContextDoc;
11714 xpctxt->contextSize = -1;
11715 xpctxt->proximityPosition = -1;
11716 return(newContextSize);
11717 }
11718 return(contextSize);
11719}
11720
11721static int
11722xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11723 xmlXPathStepOpPtr op,
11724 xmlNodeSetPtr set,
11725 int contextSize,
11726 int minPos,
11727 int maxPos,
11728 int hasNsNodes)
11729{
11730 if (op->ch1 != -1) {
11731 xmlXPathCompExprPtr comp = ctxt->comp;
11732 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11733 /*
11734 * TODO: raise an internal error.
11735 */
11736 }
11737 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11738 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11739 CHECK_ERROR0;
11740 if (contextSize <= 0)
11741 return(0);
11742 }
11743 /*
11744 * Check if the node set contains a sufficient number of nodes for
11745 * the requested range.
11746 */
11747 if (contextSize < minPos) {
11748 xmlXPathNodeSetClear(set, hasNsNodes);
11749 return(0);
11750 }
11751 if (op->ch2 == -1) {
11752 /*
11753 * TODO: Can this ever happen?
11754 */
11755 return (contextSize);
11756 } else {
11757 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011758 int i, pos = 0, newContextSize = 0, contextPos = 0, res;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011759 xmlXPathStepOpPtr exprOp;
11760 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11761 xmlNodePtr oldContextNode, contextNode = NULL;
11762 xmlXPathContextPtr xpctxt = ctxt->context;
Daniel Veillardf5048b32011-08-18 17:10:13 +080011763 int frame;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011764
11765#ifdef LIBXML_XPTR_ENABLED
11766 /*
11767 * URGENT TODO: Check the following:
11768 * We don't expect location sets if evaluating prediates, right?
11769 * Only filters should expect location sets, right?
11770 */
11771#endif /* LIBXML_XPTR_ENABLED */
11772
11773 /*
11774 * Save old context.
11775 */
11776 oldContextNode = xpctxt->node;
11777 oldContextDoc = xpctxt->doc;
11778 /*
11779 * Get the expression of this predicate.
11780 */
11781 exprOp = &ctxt->comp->steps[op->ch2];
11782 for (i = 0; i < set->nodeNr; i++) {
Daniel Veillardf5048b32011-08-18 17:10:13 +080011783 xmlXPathObjectPtr tmp;
11784
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011785 if (set->nodeTab[i] == NULL)
11786 continue;
11787
11788 contextNode = set->nodeTab[i];
11789 xpctxt->node = contextNode;
11790 xpctxt->contextSize = contextSize;
11791 xpctxt->proximityPosition = ++contextPos;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011792
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011793 /*
11794 * Initialize the new set.
11795 * Also set the xpath document in case things like
11796 * key() evaluation are attempted on the predicate
11797 */
11798 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11799 (contextNode->doc != NULL))
11800 xpctxt->doc = contextNode->doc;
11801 /*
11802 * Evaluate the predicate expression with 1 context node
11803 * at a time; this node is packaged into a node set; this
11804 * node set is handed over to the evaluation mechanism.
11805 */
11806 if (contextObj == NULL)
11807 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11808 else
11809 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11810 contextNode);
11811
Daniel Veillardf5048b32011-08-18 17:10:13 +080011812 frame = xmlXPathSetFrame(ctxt);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011813 valuePush(ctxt, contextObj);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011814 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Daniel Veillardf5048b32011-08-18 17:10:13 +080011815 tmp = valuePop(ctxt);
11816 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard45490ae2008-07-29 09:13:19 +000011817
William M. Brackf1794562007-08-23 12:58:13 +000011818 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
Daniel Veillardf5048b32011-08-18 17:10:13 +080011819 while (tmp != contextObj) {
Daniel Veillarddf83c172010-11-17 14:12:14 +010011820 /*
11821 * Free up the result
11822 * then pop off contextObj, which will be freed later
11823 */
11824 xmlXPathReleaseObject(xpctxt, tmp);
Daniel Veillardf5048b32011-08-18 17:10:13 +080011825 tmp = valuePop(ctxt);
Daniel Veillardfec31bc2010-11-18 11:07:24 +010011826 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011827 goto evaluation_error;
William M. Brackf1794562007-08-23 12:58:13 +000011828 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080011829 /* push the result back onto the stack */
11830 valuePush(ctxt, tmp);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011831
11832 if (res)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011833 pos++;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011834
11835 if (res && (pos >= minPos) && (pos <= maxPos)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011836 /*
11837 * Fits in the requested range.
11838 */
11839 newContextSize++;
11840 if (minPos == maxPos) {
11841 /*
11842 * Only 1 node was requested.
11843 */
11844 if (contextNode->type == XML_NAMESPACE_DECL) {
11845 /*
11846 * As always: take care of those nasty
11847 * namespace nodes.
11848 */
11849 set->nodeTab[i] = NULL;
11850 }
11851 xmlXPathNodeSetClear(set, hasNsNodes);
11852 set->nodeNr = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011853 set->nodeTab[0] = contextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011854 goto evaluation_exit;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011855 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011856 if (pos == maxPos) {
11857 /*
11858 * We are done.
11859 */
11860 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11861 goto evaluation_exit;
11862 }
11863 } else {
11864 /*
11865 * Remove the entry from the initial node set.
11866 */
11867 set->nodeTab[i] = NULL;
11868 if (contextNode->type == XML_NAMESPACE_DECL)
11869 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11870 }
11871 if (exprRes != NULL) {
11872 xmlXPathReleaseObject(ctxt->context, exprRes);
11873 exprRes = NULL;
11874 }
11875 if (ctxt->value == contextObj) {
11876 /*
11877 * Don't free the temporary XPath object holding the
11878 * context node, in order to avoid massive recreation
11879 * inside this loop.
11880 */
11881 valuePop(ctxt);
11882 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11883 } else {
11884 /*
11885 * The object was lost in the evaluation machinery.
11886 * Can this happen? Maybe in case of internal-errors.
11887 */
11888 contextObj = NULL;
11889 }
11890 }
11891 goto evaluation_exit;
11892
11893evaluation_error:
11894 xmlXPathNodeSetClear(set, hasNsNodes);
11895 newContextSize = 0;
11896
11897evaluation_exit:
11898 if (contextObj != NULL) {
11899 if (ctxt->value == contextObj)
11900 valuePop(ctxt);
11901 xmlXPathReleaseObject(xpctxt, contextObj);
11902 }
11903 if (exprRes != NULL)
11904 xmlXPathReleaseObject(ctxt->context, exprRes);
11905 /*
11906 * Reset/invalidate the context.
11907 */
11908 xpctxt->node = oldContextNode;
11909 xpctxt->doc = oldContextDoc;
11910 xpctxt->contextSize = -1;
11911 xpctxt->proximityPosition = -1;
11912 return(newContextSize);
11913 }
11914 return(contextSize);
11915}
11916
11917static int
11918xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
Daniel Veillard45490ae2008-07-29 09:13:19 +000011919 xmlXPathStepOpPtr op,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011920 int *maxPos)
11921{
11922
11923 xmlXPathStepOpPtr exprOp;
11924
11925 /*
11926 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11927 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000011928
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011929 /*
11930 * If not -1, then ch1 will point to:
11931 * 1) For predicates (XPATH_OP_PREDICATE):
11932 * - an inner predicate operator
11933 * 2) For filters (XPATH_OP_FILTER):
11934 * - an inner filter operater OR
11935 * - an expression selecting the node set.
11936 * E.g. "key('a', 'b')" or "(//foo | //bar)".
Daniel Veillard45490ae2008-07-29 09:13:19 +000011937 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011938 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11939 return(0);
11940
11941 if (op->ch2 != -1) {
11942 exprOp = &ctxt->comp->steps[op->ch2];
Daniel Veillard45490ae2008-07-29 09:13:19 +000011943 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011944 return(0);
11945
11946 if ((exprOp != NULL) &&
11947 (exprOp->op == XPATH_OP_VALUE) &&
11948 (exprOp->value4 != NULL) &&
11949 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11950 {
11951 /*
11952 * We have a "[n]" predicate here.
11953 * TODO: Unfortunately this simplistic test here is not
11954 * able to detect a position() predicate in compound
11955 * expressions like "[@attr = 'a" and position() = 1],
11956 * and even not the usage of position() in
11957 * "[position() = 1]"; thus - obviously - a position-range,
11958 * like it "[position() < 5]", is also not detected.
11959 * Maybe we could rewrite the AST to ease the optimization.
11960 */
11961 *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
Daniel Veillard45490ae2008-07-29 09:13:19 +000011962
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011963 if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
11964 (float) *maxPos)
Daniel Veillard45490ae2008-07-29 09:13:19 +000011965 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011966 return(1);
11967 }
11968 }
11969 return(0);
11970}
11971
11972static int
11973xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11974 xmlXPathStepOpPtr op,
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011975 xmlNodePtr * first, xmlNodePtr * last,
11976 int toBool)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011977{
11978
11979#define XP_TEST_HIT \
11980 if (hasAxisRange != 0) { \
11981 if (++pos == maxPos) { \
11982 addNode(seq, cur); \
11983 goto axis_range_end; } \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011984 } else { \
11985 addNode(seq, cur); \
11986 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011987
11988#define XP_TEST_HIT_NS \
11989 if (hasAxisRange != 0) { \
11990 if (++pos == maxPos) { \
11991 hasNsNodes = 1; \
11992 xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
11993 goto axis_range_end; } \
11994 } else { \
11995 hasNsNodes = 1; \
11996 xmlXPathNodeSetAddNs(seq, \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011997 xpctxt->node, (xmlNsPtr) cur); \
11998 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011999
12000 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
12001 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12002 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12003 const xmlChar *prefix = op->value4;
12004 const xmlChar *name = op->value5;
12005 const xmlChar *URI = NULL;
12006
12007#ifdef DEBUG_STEP
12008 int nbMatches = 0, prevMatches = 0;
12009#endif
12010 int total = 0, hasNsNodes = 0;
12011 /* The popped object holding the context nodes */
12012 xmlXPathObjectPtr obj;
12013 /* The set of context nodes for the node tests */
12014 xmlNodeSetPtr contextSeq;
12015 int contextIdx;
12016 xmlNodePtr contextNode;
12017 /* The context node for a compound traversal */
12018 xmlNodePtr outerContextNode;
12019 /* The final resulting node set wrt to all context nodes */
12020 xmlNodeSetPtr outSeq;
12021 /*
12022 * The temporary resulting node set wrt 1 context node.
12023 * Used to feed predicate evaluation.
12024 */
12025 xmlNodeSetPtr seq;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012026 xmlNodePtr cur;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012027 /* First predicate operator */
12028 xmlXPathStepOpPtr predOp;
12029 int maxPos; /* The requested position() (when a "[n]" predicate) */
12030 int hasPredicateRange, hasAxisRange, pos, size, newSize;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012031 int breakOnFirstHit;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012032
12033 xmlXPathTraversalFunction next = NULL;
12034 /* compound axis traversal */
12035 xmlXPathTraversalFunctionExt outerNext = NULL;
12036 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12037 xmlXPathNodeSetMergeFunction mergeAndClear;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012038 xmlNodePtr oldContextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012039 xmlXPathContextPtr xpctxt = ctxt->context;
12040
12041
12042 CHECK_TYPE0(XPATH_NODESET);
12043 obj = valuePop(ctxt);
12044 /*
12045 * Setup namespaces.
12046 */
12047 if (prefix != NULL) {
12048 URI = xmlXPathNsLookup(xpctxt, prefix);
12049 if (URI == NULL) {
12050 xmlXPathReleaseObject(xpctxt, obj);
12051 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12052 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012053 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012054 /*
12055 * Setup axis.
12056 *
12057 * MAYBE FUTURE TODO: merging optimizations:
12058 * - If the nodes to be traversed wrt to the initial nodes and
12059 * the current axis cannot overlap, then we could avoid searching
12060 * for duplicates during the merge.
12061 * But the question is how/when to evaluate if they cannot overlap.
12062 * Example: if we know that for two initial nodes, the one is
12063 * not in the ancestor-or-self axis of the other, then we could safely
12064 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12065 * the descendant-or-self axis.
12066 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012067 mergeAndClear = xmlXPathNodeSetMergeAndClear;
12068 switch (axis) {
12069 case AXIS_ANCESTOR:
12070 first = NULL;
12071 next = xmlXPathNextAncestor;
12072 break;
12073 case AXIS_ANCESTOR_OR_SELF:
12074 first = NULL;
12075 next = xmlXPathNextAncestorOrSelf;
12076 break;
12077 case AXIS_ATTRIBUTE:
12078 first = NULL;
12079 last = NULL;
12080 next = xmlXPathNextAttribute;
12081 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12082 break;
12083 case AXIS_CHILD:
12084 last = NULL;
12085 if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
12086 /*
12087 * This iterator will give us only nodes which can
12088 * hold element nodes.
12089 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000012090 outerNext = xmlXPathNextDescendantOrSelfElemParent;
12091 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012092 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12093 (type == NODE_TYPE_NODE))
12094 {
12095 /*
12096 * Optimization if an element node type is 'element'.
12097 */
12098 next = xmlXPathNextChildElement;
12099 } else
12100 next = xmlXPathNextChild;
12101 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12102 break;
12103 case AXIS_DESCENDANT:
12104 last = NULL;
12105 next = xmlXPathNextDescendant;
12106 break;
12107 case AXIS_DESCENDANT_OR_SELF:
12108 last = NULL;
12109 next = xmlXPathNextDescendantOrSelf;
12110 break;
12111 case AXIS_FOLLOWING:
12112 last = NULL;
12113 next = xmlXPathNextFollowing;
12114 break;
12115 case AXIS_FOLLOWING_SIBLING:
12116 last = NULL;
12117 next = xmlXPathNextFollowingSibling;
12118 break;
12119 case AXIS_NAMESPACE:
12120 first = NULL;
12121 last = NULL;
12122 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12123 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12124 break;
12125 case AXIS_PARENT:
12126 first = NULL;
12127 next = xmlXPathNextParent;
12128 break;
12129 case AXIS_PRECEDING:
12130 first = NULL;
12131 next = xmlXPathNextPrecedingInternal;
12132 break;
12133 case AXIS_PRECEDING_SIBLING:
12134 first = NULL;
12135 next = xmlXPathNextPrecedingSibling;
12136 break;
12137 case AXIS_SELF:
12138 first = NULL;
12139 last = NULL;
12140 next = xmlXPathNextSelf;
12141 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12142 break;
12143 }
12144
12145#ifdef DEBUG_STEP
Daniel Veillard074f37e2008-09-01 13:38:22 +000012146 xmlXPathDebugDumpStepAxis(op,
12147 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012148#endif
12149
12150 if (next == NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000012151 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012152 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012153 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012154 contextSeq = obj->nodesetval;
12155 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12156 xmlXPathReleaseObject(xpctxt, obj);
12157 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12158 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012159 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012160 /*
12161 * Predicate optimization ---------------------------------------------
12162 * If this step has a last predicate, which contains a position(),
12163 * then we'll optimize (although not exactly "position()", but only
12164 * the short-hand form, i.e., "[n]".
12165 *
12166 * Example - expression "/foo[parent::bar][1]":
Daniel Veillard45490ae2008-07-29 09:13:19 +000012167 *
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012168 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12169 * ROOT -- op->ch1
12170 * PREDICATE -- op->ch2 (predOp)
12171 * PREDICATE -- predOp->ch1 = [parent::bar]
12172 * SORT
12173 * COLLECT 'parent' 'name' 'node' bar
12174 * NODE
12175 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12176 *
12177 */
12178 maxPos = 0;
12179 predOp = NULL;
12180 hasPredicateRange = 0;
12181 hasAxisRange = 0;
12182 if (op->ch2 != -1) {
12183 /*
12184 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12185 */
12186 predOp = &ctxt->comp->steps[op->ch2];
12187 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12188 if (predOp->ch1 != -1) {
12189 /*
12190 * Use the next inner predicate operator.
12191 */
12192 predOp = &ctxt->comp->steps[predOp->ch1];
12193 hasPredicateRange = 1;
12194 } else {
12195 /*
12196 * There's no other predicate than the [n] predicate.
12197 */
12198 predOp = NULL;
12199 hasAxisRange = 1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012200 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012201 }
12202 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012203 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012204 /*
12205 * Axis traversal -----------------------------------------------------
12206 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012207 /*
12208 * 2.3 Node Tests
Daniel Veillard45490ae2008-07-29 09:13:19 +000012209 * - For the attribute axis, the principal node type is attribute.
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012210 * - For the namespace axis, the principal node type is namespace.
12211 * - For other axes, the principal node type is element.
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012212 *
12213 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012214 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012215 * select all element children of the context node
12216 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012217 oldContextNode = xpctxt->node;
12218 addNode = xmlXPathNodeSetAddUnique;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012219 outSeq = NULL;
12220 seq = NULL;
12221 outerContextNode = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012222 contextNode = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012223 contextIdx = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012224
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012225
12226 while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
12227 if (outerNext != NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012228 /*
12229 * This is a compound traversal.
12230 */
12231 if (contextNode == NULL) {
12232 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012233 * Set the context for the outer traversal.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012234 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012235 outerContextNode = contextSeq->nodeTab[contextIdx++];
12236 contextNode = outerNext(NULL, outerContextNode);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012237 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012238 contextNode = outerNext(contextNode, outerContextNode);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012239 if (contextNode == NULL)
12240 continue;
12241 /*
12242 * Set the context for the main traversal.
12243 */
12244 xpctxt->node = contextNode;
12245 } else
Daniel Veillard45490ae2008-07-29 09:13:19 +000012246 xpctxt->node = contextSeq->nodeTab[contextIdx++];
12247
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012248 if (seq == NULL) {
12249 seq = xmlXPathNodeSetCreate(NULL);
12250 if (seq == NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012251 total = 0;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012252 goto error;
12253 }
12254 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012255 /*
12256 * Traverse the axis and test the nodes.
12257 */
12258 pos = 0;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012259 cur = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012260 hasNsNodes = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012261 do {
12262 cur = next(ctxt, cur);
12263 if (cur == NULL)
12264 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012265
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012266 /*
12267 * QUESTION TODO: What does the "first" and "last" stuff do?
12268 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012269 if ((first != NULL) && (*first != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012270 if (*first == cur)
12271 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012272 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012273#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012274 (xmlXPathCmpNodesExt(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012275#else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012276 (xmlXPathCmpNodes(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012277#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012278 {
12279 break;
12280 }
12281 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012282 if ((last != NULL) && (*last != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012283 if (*last == cur)
12284 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012285 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012286#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012287 (xmlXPathCmpNodesExt(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012288#else
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012289 (xmlXPathCmpNodes(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012290#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012291 {
12292 break;
12293 }
12294 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012295
12296 total++;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012297
Daniel Veillardf06307e2001-07-03 10:35:50 +000012298#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012299 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12300#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +000012301
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012302 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012303 case NODE_TEST_NONE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012304 total = 0;
12305 STRANGE
12306 goto error;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012307 case NODE_TEST_TYPE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012308 /*
12309 * TODO: Don't we need to use
12310 * xmlXPathNodeSetAddNs() for namespace nodes here?
12311 * Surprisingly, some c14n tests fail, if we do this.
12312 */
12313 if (type == NODE_TYPE_NODE) {
12314 switch (cur->type) {
12315 case XML_DOCUMENT_NODE:
12316 case XML_HTML_DOCUMENT_NODE:
12317#ifdef LIBXML_DOCB_ENABLED
12318 case XML_DOCB_DOCUMENT_NODE:
12319#endif
Daniel Veillard45490ae2008-07-29 09:13:19 +000012320 case XML_ELEMENT_NODE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012321 case XML_ATTRIBUTE_NODE:
12322 case XML_PI_NODE:
12323 case XML_COMMENT_NODE:
12324 case XML_CDATA_SECTION_NODE:
12325 case XML_TEXT_NODE:
12326 case XML_NAMESPACE_DECL:
12327 XP_TEST_HIT
12328 break;
12329 default:
12330 break;
12331 }
12332 } else if (cur->type == type) {
Kasimier T. Buchcik889b7622006-07-03 11:44:13 +000012333 if (type == XML_NAMESPACE_DECL)
12334 XP_TEST_HIT_NS
12335 else
12336 XP_TEST_HIT
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012337 } else if ((type == NODE_TYPE_TEXT) &&
12338 (cur->type == XML_CDATA_SECTION_NODE))
12339 {
12340 XP_TEST_HIT
12341 }
12342 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012343 case NODE_TEST_PI:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012344 if ((cur->type == XML_PI_NODE) &&
12345 ((name == NULL) || xmlStrEqual(name, cur->name)))
12346 {
12347 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012348 }
12349 break;
12350 case NODE_TEST_ALL:
12351 if (axis == AXIS_ATTRIBUTE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012352 if (cur->type == XML_ATTRIBUTE_NODE)
12353 {
12354 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012355 }
12356 } else if (axis == AXIS_NAMESPACE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012357 if (cur->type == XML_NAMESPACE_DECL)
12358 {
12359 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012360 }
12361 } else {
12362 if (cur->type == XML_ELEMENT_NODE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012363 if (prefix == NULL)
12364 {
12365 XP_TEST_HIT
12366
Daniel Veillardf06307e2001-07-03 10:35:50 +000012367 } else if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012368 (xmlStrEqual(URI, cur->ns->href)))
12369 {
12370 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012371 }
12372 }
12373 }
12374 break;
12375 case NODE_TEST_NS:{
12376 TODO;
12377 break;
12378 }
12379 case NODE_TEST_NAME:
Daniel Veillardfe3970e2006-11-23 16:08:30 +000012380 if (axis == AXIS_ATTRIBUTE) {
12381 if (cur->type != XML_ATTRIBUTE_NODE)
12382 break;
12383 } else if (axis == AXIS_NAMESPACE) {
12384 if (cur->type != XML_NAMESPACE_DECL)
12385 break;
12386 } else {
12387 if (cur->type != XML_ELEMENT_NODE)
12388 break;
12389 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012390 switch (cur->type) {
12391 case XML_ELEMENT_NODE:
12392 if (xmlStrEqual(name, cur->name)) {
12393 if (prefix == NULL) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012394 if (cur->ns == NULL)
12395 {
12396 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012397 }
12398 } else {
12399 if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012400 (xmlStrEqual(URI, cur->ns->href)))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012401 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012402 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012403 }
12404 }
12405 }
12406 break;
12407 case XML_ATTRIBUTE_NODE:{
12408 xmlAttrPtr attr = (xmlAttrPtr) cur;
12409
12410 if (xmlStrEqual(name, attr->name)) {
12411 if (prefix == NULL) {
12412 if ((attr->ns == NULL) ||
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012413 (attr->ns->prefix == NULL))
12414 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012415 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012416 }
12417 } else {
12418 if ((attr->ns != NULL) &&
12419 (xmlStrEqual(URI,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012420 attr->ns->href)))
12421 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012422 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012423 }
12424 }
12425 }
12426 break;
12427 }
12428 case XML_NAMESPACE_DECL:
12429 if (cur->type == XML_NAMESPACE_DECL) {
12430 xmlNsPtr ns = (xmlNsPtr) cur;
12431
12432 if ((ns->prefix != NULL) && (name != NULL)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012433 && (xmlStrEqual(ns->prefix, name)))
12434 {
12435 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012436 }
12437 }
12438 break;
12439 default:
12440 break;
12441 }
12442 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012443 } /* switch(test) */
12444 } while (cur != NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012445
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012446 goto apply_predicates;
12447
Daniel Veillard45490ae2008-07-29 09:13:19 +000012448axis_range_end: /* ----------------------------------------------------- */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012449 /*
12450 * We have a "/foo[n]", and position() = n was reached.
12451 * Note that we can have as well "/foo/::parent::foo[1]", so
12452 * a duplicate-aware merge is still needed.
12453 * Merge with the result.
12454 */
12455 if (outSeq == NULL) {
12456 outSeq = seq;
12457 seq = NULL;
12458 } else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012459 outSeq = mergeAndClear(outSeq, seq, 0);
12460 /*
12461 * Break if only a true/false result was requested.
12462 */
12463 if (toBool)
12464 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012465 continue;
12466
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012467first_hit: /* ---------------------------------------------------------- */
12468 /*
12469 * Break if only a true/false result was requested and
12470 * no predicates existed and a node test succeeded.
12471 */
12472 if (outSeq == NULL) {
12473 outSeq = seq;
12474 seq = NULL;
12475 } else
12476 outSeq = mergeAndClear(outSeq, seq, 0);
12477 break;
12478
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012479#ifdef DEBUG_STEP
12480 if (seq != NULL)
12481 nbMatches += seq->nodeNr;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012482#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012483
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012484apply_predicates: /* --------------------------------------------------- */
12485 /*
12486 * Apply predicates.
Daniel Veillard45490ae2008-07-29 09:13:19 +000012487 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012488 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12489 /*
12490 * E.g. when we have a "/foo[some expression][n]".
Daniel Veillard45490ae2008-07-29 09:13:19 +000012491 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012492 /*
12493 * QUESTION TODO: The old predicate evaluation took into
12494 * account location-sets.
12495 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12496 * Do we expect such a set here?
12497 * All what I learned now from the evaluation semantics
12498 * does not indicate that a location-set will be processed
12499 * here, so this looks OK.
Daniel Veillard45490ae2008-07-29 09:13:19 +000012500 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012501 /*
12502 * Iterate over all predicates, starting with the outermost
12503 * predicate.
12504 * TODO: Problem: we cannot execute the inner predicates first
12505 * since we cannot go back *up* the operator tree!
12506 * Options we have:
12507 * 1) Use of recursive functions (like is it currently done
12508 * via xmlXPathCompOpEval())
12509 * 2) Add a predicate evaluation information stack to the
12510 * context struct
12511 * 3) Change the way the operators are linked; we need a
12512 * "parent" field on xmlXPathStepOp
12513 *
12514 * For the moment, I'll try to solve this with a recursive
12515 * function: xmlXPathCompOpEvalPredicate().
Daniel Veillard45490ae2008-07-29 09:13:19 +000012516 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012517 size = seq->nodeNr;
12518 if (hasPredicateRange != 0)
12519 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12520 predOp, seq, size, maxPos, maxPos, hasNsNodes);
12521 else
12522 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12523 predOp, seq, size, hasNsNodes);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012524
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012525 if (ctxt->error != XPATH_EXPRESSION_OK) {
12526 total = 0;
12527 goto error;
12528 }
12529 /*
12530 * Add the filtered set of nodes to the result node set.
12531 */
12532 if (newSize == 0) {
12533 /*
12534 * The predicates filtered all nodes out.
12535 */
12536 xmlXPathNodeSetClear(seq, hasNsNodes);
12537 } else if (seq->nodeNr > 0) {
12538 /*
12539 * Add to result set.
12540 */
12541 if (outSeq == NULL) {
12542 if (size != newSize) {
12543 /*
12544 * We need to merge and clear here, since
12545 * the sequence will contained NULLed entries.
12546 */
12547 outSeq = mergeAndClear(NULL, seq, 1);
12548 } else {
12549 outSeq = seq;
12550 seq = NULL;
12551 }
12552 } else
12553 outSeq = mergeAndClear(outSeq, seq,
12554 (size != newSize) ? 1: 0);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012555 /*
12556 * Break if only a true/false result was requested.
12557 */
12558 if (toBool)
12559 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012560 }
12561 } else if (seq->nodeNr > 0) {
12562 /*
12563 * Add to result set.
12564 */
12565 if (outSeq == NULL) {
12566 outSeq = seq;
12567 seq = NULL;
12568 } else {
12569 outSeq = mergeAndClear(outSeq, seq, 0);
12570 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012571 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012572 }
12573
12574error:
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012575 if ((obj->boolval) && (obj->user != NULL)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012576 /*
12577 * QUESTION TODO: What does this do and why?
12578 * TODO: Do we have to do this also for the "error"
12579 * cleanup further down?
12580 */
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012581 ctxt->value->boolval = 1;
12582 ctxt->value->user = obj->user;
12583 obj->user = NULL;
12584 obj->boolval = 0;
12585 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012586 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012587
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012588 /*
12589 * Ensure we return at least an emtpy set.
12590 */
12591 if (outSeq == NULL) {
12592 if ((seq != NULL) && (seq->nodeNr == 0))
12593 outSeq = seq;
12594 else
12595 outSeq = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +000012596 /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012597 }
12598 if ((seq != NULL) && (seq != outSeq)) {
12599 xmlXPathFreeNodeSet(seq);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012600 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012601 /*
12602 * Hand over the result. Better to push the set also in
12603 * case of errors.
12604 */
12605 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12606 /*
12607 * Reset the context node.
12608 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012609 xpctxt->node = oldContextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012610
12611#ifdef DEBUG_STEP
12612 xmlGenericError(xmlGenericErrorContext,
12613 "\nExamined %d nodes, found %d nodes at that step\n",
12614 total, nbMatches);
12615#endif
12616
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012617 return(total);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012618}
12619
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012620static int
12621xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12622 xmlXPathStepOpPtr op, xmlNodePtr * first);
12623
Daniel Veillardf06307e2001-07-03 10:35:50 +000012624/**
12625 * xmlXPathCompOpEvalFirst:
12626 * @ctxt: the XPath parser context with the compiled expression
12627 * @op: an XPath compiled operation
12628 * @first: the first elem found so far
12629 *
12630 * Evaluate the Precompiled XPath operation searching only the first
12631 * element in document order
12632 *
12633 * Returns the number of examined objects.
12634 */
12635static int
12636xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12637 xmlXPathStepOpPtr op, xmlNodePtr * first)
12638{
12639 int total = 0, cur;
12640 xmlXPathCompExprPtr comp;
12641 xmlXPathObjectPtr arg1, arg2;
12642
Daniel Veillard556c6682001-10-06 09:59:51 +000012643 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012644 comp = ctxt->comp;
12645 switch (op->op) {
12646 case XPATH_OP_END:
12647 return (0);
12648 case XPATH_OP_UNION:
12649 total =
12650 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12651 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012652 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012653 if ((ctxt->value != NULL)
12654 && (ctxt->value->type == XPATH_NODESET)
12655 && (ctxt->value->nodesetval != NULL)
12656 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12657 /*
12658 * limit tree traversing to first node in the result
12659 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012660 /*
12661 * OPTIMIZE TODO: This implicitely sorts
12662 * the result, even if not needed. E.g. if the argument
12663 * of the count() function, no sorting is needed.
12664 * OPTIMIZE TODO: How do we know if the node-list wasn't
12665 * aready sorted?
12666 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012667 if (ctxt->value->nodesetval->nodeNr > 1)
12668 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012669 *first = ctxt->value->nodesetval->nodeTab[0];
12670 }
12671 cur =
12672 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12673 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012674 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012675 CHECK_TYPE0(XPATH_NODESET);
12676 arg2 = valuePop(ctxt);
12677
12678 CHECK_TYPE0(XPATH_NODESET);
12679 arg1 = valuePop(ctxt);
12680
12681 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12682 arg2->nodesetval);
12683 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012684 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012685 /* optimizer */
12686 if (total > cur)
12687 xmlXPathCompSwap(op);
12688 return (total + cur);
12689 case XPATH_OP_ROOT:
12690 xmlXPathRoot(ctxt);
12691 return (0);
12692 case XPATH_OP_NODE:
12693 if (op->ch1 != -1)
12694 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012695 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012696 if (op->ch2 != -1)
12697 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012698 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012699 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12700 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012701 return (total);
12702 case XPATH_OP_RESET:
12703 if (op->ch1 != -1)
12704 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012705 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012706 if (op->ch2 != -1)
12707 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012708 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012709 ctxt->context->node = NULL;
12710 return (total);
12711 case XPATH_OP_COLLECT:{
12712 if (op->ch1 == -1)
12713 return (total);
12714
12715 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012716 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012717
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012718 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012719 return (total);
12720 }
12721 case XPATH_OP_VALUE:
12722 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012723 xmlXPathCacheObjectCopy(ctxt->context,
12724 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012725 return (0);
12726 case XPATH_OP_SORT:
12727 if (op->ch1 != -1)
12728 total +=
12729 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12730 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012731 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012732 if ((ctxt->value != NULL)
12733 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012734 && (ctxt->value->nodesetval != NULL)
12735 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012736 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12737 return (total);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012738#ifdef XP_OPTIMIZED_FILTER_FIRST
12739 case XPATH_OP_FILTER:
Marius Wachtler2ddecc22010-10-12 09:09:07 +020012740 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012741 return (total);
12742#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000012743 default:
12744 return (xmlXPathCompOpEval(ctxt, op));
12745 }
12746}
12747
12748/**
12749 * xmlXPathCompOpEvalLast:
12750 * @ctxt: the XPath parser context with the compiled expression
12751 * @op: an XPath compiled operation
12752 * @last: the last elem found so far
12753 *
12754 * Evaluate the Precompiled XPath operation searching only the last
12755 * element in document order
12756 *
William M. Brack08171912003-12-29 02:52:11 +000012757 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000012758 */
12759static int
12760xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12761 xmlNodePtr * last)
12762{
12763 int total = 0, cur;
12764 xmlXPathCompExprPtr comp;
12765 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +000012766 xmlNodePtr bak;
12767 xmlDocPtr bakd;
12768 int pp;
12769 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012770
Daniel Veillard556c6682001-10-06 09:59:51 +000012771 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012772 comp = ctxt->comp;
12773 switch (op->op) {
12774 case XPATH_OP_END:
12775 return (0);
12776 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +000012777 bakd = ctxt->context->doc;
12778 bak = ctxt->context->node;
12779 pp = ctxt->context->proximityPosition;
12780 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012781 total =
12782 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012783 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012784 if ((ctxt->value != NULL)
12785 && (ctxt->value->type == XPATH_NODESET)
12786 && (ctxt->value->nodesetval != NULL)
12787 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12788 /*
12789 * limit tree traversing to first node in the result
12790 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012791 if (ctxt->value->nodesetval->nodeNr > 1)
12792 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012793 *last =
12794 ctxt->value->nodesetval->nodeTab[ctxt->value->
12795 nodesetval->nodeNr -
12796 1];
12797 }
William M. Brackce4fc562004-01-22 02:47:18 +000012798 ctxt->context->doc = bakd;
12799 ctxt->context->node = bak;
12800 ctxt->context->proximityPosition = pp;
12801 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012802 cur =
12803 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012804 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012805 if ((ctxt->value != NULL)
12806 && (ctxt->value->type == XPATH_NODESET)
12807 && (ctxt->value->nodesetval != NULL)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012808 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012809 }
12810 CHECK_TYPE0(XPATH_NODESET);
12811 arg2 = valuePop(ctxt);
12812
12813 CHECK_TYPE0(XPATH_NODESET);
12814 arg1 = valuePop(ctxt);
12815
12816 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12817 arg2->nodesetval);
12818 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012819 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012820 /* optimizer */
12821 if (total > cur)
12822 xmlXPathCompSwap(op);
12823 return (total + cur);
12824 case XPATH_OP_ROOT:
12825 xmlXPathRoot(ctxt);
12826 return (0);
12827 case XPATH_OP_NODE:
12828 if (op->ch1 != -1)
12829 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012830 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012831 if (op->ch2 != -1)
12832 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012833 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012834 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12835 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012836 return (total);
12837 case XPATH_OP_RESET:
12838 if (op->ch1 != -1)
12839 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012840 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012841 if (op->ch2 != -1)
12842 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012843 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012844 ctxt->context->node = NULL;
12845 return (total);
12846 case XPATH_OP_COLLECT:{
12847 if (op->ch1 == -1)
12848 return (0);
12849
12850 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012851 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012852
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012853 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012854 return (total);
12855 }
12856 case XPATH_OP_VALUE:
12857 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012858 xmlXPathCacheObjectCopy(ctxt->context,
12859 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012860 return (0);
12861 case XPATH_OP_SORT:
12862 if (op->ch1 != -1)
12863 total +=
12864 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12865 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012866 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012867 if ((ctxt->value != NULL)
12868 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012869 && (ctxt->value->nodesetval != NULL)
12870 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012871 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12872 return (total);
12873 default:
12874 return (xmlXPathCompOpEval(ctxt, op));
12875 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012876}
12877
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012878#ifdef XP_OPTIMIZED_FILTER_FIRST
12879static int
12880xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12881 xmlXPathStepOpPtr op, xmlNodePtr * first)
12882{
12883 int total = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012884 xmlXPathCompExprPtr comp;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012885 xmlXPathObjectPtr res;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012886 xmlXPathObjectPtr obj;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012887 xmlNodeSetPtr oldset;
12888 xmlNodePtr oldnode;
12889 xmlDocPtr oldDoc;
12890 int i;
12891
12892 CHECK_ERROR0;
12893 comp = ctxt->comp;
12894 /*
12895 * Optimization for ()[last()] selection i.e. the last elem
12896 */
12897 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12898 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12899 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12900 int f = comp->steps[op->ch2].ch1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012901
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012902 if ((f != -1) &&
12903 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12904 (comp->steps[f].value5 == NULL) &&
12905 (comp->steps[f].value == 0) &&
12906 (comp->steps[f].value4 != NULL) &&
12907 (xmlStrEqual
12908 (comp->steps[f].value4, BAD_CAST "last"))) {
12909 xmlNodePtr last = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012910
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012911 total +=
12912 xmlXPathCompOpEvalLast(ctxt,
12913 &comp->steps[op->ch1],
12914 &last);
12915 CHECK_ERROR0;
12916 /*
12917 * The nodeset should be in document order,
12918 * Keep only the last value
12919 */
12920 if ((ctxt->value != NULL) &&
12921 (ctxt->value->type == XPATH_NODESET) &&
12922 (ctxt->value->nodesetval != NULL) &&
12923 (ctxt->value->nodesetval->nodeTab != NULL) &&
12924 (ctxt->value->nodesetval->nodeNr > 1)) {
12925 ctxt->value->nodesetval->nodeTab[0] =
12926 ctxt->value->nodesetval->nodeTab[ctxt->
12927 value->
12928 nodesetval->
12929 nodeNr -
12930 1];
12931 ctxt->value->nodesetval->nodeNr = 1;
12932 *first = *(ctxt->value->nodesetval->nodeTab);
12933 }
12934 return (total);
12935 }
12936 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000012937
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012938 if (op->ch1 != -1)
12939 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12940 CHECK_ERROR0;
12941 if (op->ch2 == -1)
12942 return (total);
12943 if (ctxt->value == NULL)
12944 return (total);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012945
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012946#ifdef LIBXML_XPTR_ENABLED
12947 oldnode = ctxt->context->node;
12948 /*
12949 * Hum are we filtering the result of an XPointer expression
12950 */
12951 if (ctxt->value->type == XPATH_LOCATIONSET) {
12952 xmlXPathObjectPtr tmp = NULL;
12953 xmlLocationSetPtr newlocset = NULL;
12954 xmlLocationSetPtr oldlocset;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012955
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012956 /*
12957 * Extract the old locset, and then evaluate the result of the
12958 * expression for all the element in the locset. use it to grow
12959 * up a new locset.
12960 */
12961 CHECK_TYPE0(XPATH_LOCATIONSET);
12962 obj = valuePop(ctxt);
12963 oldlocset = obj->user;
12964 ctxt->context->node = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000012965
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012966 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12967 ctxt->context->contextSize = 0;
12968 ctxt->context->proximityPosition = 0;
12969 if (op->ch2 != -1)
12970 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12971 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012972 if (res != NULL) {
12973 xmlXPathReleaseObject(ctxt->context, res);
12974 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012975 valuePush(ctxt, obj);
12976 CHECK_ERROR0;
12977 return (total);
12978 }
12979 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012980
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012981 for (i = 0; i < oldlocset->locNr; i++) {
12982 /*
12983 * Run the evaluation with a node list made of a
12984 * single item in the nodelocset.
12985 */
12986 ctxt->context->node = oldlocset->locTab[i]->user;
12987 ctxt->context->contextSize = oldlocset->locNr;
12988 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012989 if (tmp == NULL) {
12990 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12991 ctxt->context->node);
12992 } else {
12993 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12994 ctxt->context->node);
Daniel Veillard45490ae2008-07-29 09:13:19 +000012995 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012996 valuePush(ctxt, tmp);
12997 if (op->ch2 != -1)
12998 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12999 if (ctxt->error != XPATH_EXPRESSION_OK) {
13000 xmlXPathFreeObject(obj);
13001 return(0);
13002 }
13003 /*
13004 * The result of the evaluation need to be tested to
13005 * decided whether the filter succeeded or not
13006 */
13007 res = valuePop(ctxt);
13008 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13009 xmlXPtrLocationSetAdd(newlocset,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013010 xmlXPathCacheObjectCopy(ctxt->context,
13011 oldlocset->locTab[i]));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013012 }
13013 /*
13014 * Cleanup
13015 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013016 if (res != NULL) {
13017 xmlXPathReleaseObject(ctxt->context, res);
13018 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013019 if (ctxt->value == tmp) {
13020 valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013021 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013022 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013023 * REVISIT TODO: Don't create a temporary nodeset
13024 * for everly iteration.
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013025 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013026 /* OLD: xmlXPathFreeObject(res); */
13027 } else
Daniel Veillard45490ae2008-07-29 09:13:19 +000013028 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013029 ctxt->context->node = NULL;
13030 /*
13031 * Only put the first node in the result, then leave.
13032 */
13033 if (newlocset->locNr > 0) {
13034 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
13035 break;
13036 }
13037 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013038 if (tmp != NULL) {
13039 xmlXPathReleaseObject(ctxt->context, tmp);
13040 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013041 /*
13042 * The result is used as the new evaluation locset.
13043 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013044 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013045 ctxt->context->node = NULL;
13046 ctxt->context->contextSize = -1;
13047 ctxt->context->proximityPosition = -1;
13048 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13049 ctxt->context->node = oldnode;
13050 return (total);
13051 }
13052#endif /* LIBXML_XPTR_ENABLED */
Daniel Veillard45490ae2008-07-29 09:13:19 +000013053
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013054 /*
13055 * Extract the old set, and then evaluate the result of the
13056 * expression for all the element in the set. use it to grow
13057 * up a new set.
13058 */
13059 CHECK_TYPE0(XPATH_NODESET);
13060 obj = valuePop(ctxt);
13061 oldset = obj->nodesetval;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013062
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013063 oldnode = ctxt->context->node;
13064 oldDoc = ctxt->context->doc;
13065 ctxt->context->node = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000013066
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013067 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13068 ctxt->context->contextSize = 0;
13069 ctxt->context->proximityPosition = 0;
13070 /* QUESTION TODO: Why was this code commented out?
13071 if (op->ch2 != -1)
13072 total +=
13073 xmlXPathCompOpEval(ctxt,
13074 &comp->steps[op->ch2]);
13075 CHECK_ERROR0;
13076 res = valuePop(ctxt);
13077 if (res != NULL)
13078 xmlXPathFreeObject(res);
13079 */
13080 valuePush(ctxt, obj);
13081 ctxt->context->node = oldnode;
13082 CHECK_ERROR0;
13083 } else {
13084 xmlNodeSetPtr newset;
13085 xmlXPathObjectPtr tmp = NULL;
13086 /*
13087 * Initialize the new set.
13088 * Also set the xpath document in case things like
13089 * key() evaluation are attempted on the predicate
Daniel Veillard45490ae2008-07-29 09:13:19 +000013090 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013091 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillardf88d8492008-04-01 08:00:31 +000013092 /* XXX what if xmlXPathNodeSetCreate returned NULL? */
Daniel Veillard45490ae2008-07-29 09:13:19 +000013093
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013094 for (i = 0; i < oldset->nodeNr; i++) {
13095 /*
13096 * Run the evaluation with a node list made of
13097 * a single item in the nodeset.
13098 */
13099 ctxt->context->node = oldset->nodeTab[i];
13100 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13101 (oldset->nodeTab[i]->doc != NULL))
13102 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013103 if (tmp == NULL) {
13104 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13105 ctxt->context->node);
13106 } else {
13107 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13108 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013109 }
13110 valuePush(ctxt, tmp);
13111 ctxt->context->contextSize = oldset->nodeNr;
13112 ctxt->context->proximityPosition = i + 1;
13113 if (op->ch2 != -1)
13114 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13115 if (ctxt->error != XPATH_EXPRESSION_OK) {
13116 xmlXPathFreeNodeSet(newset);
13117 xmlXPathFreeObject(obj);
13118 return(0);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013119 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013120 /*
13121 * The result of the evaluation needs to be tested to
13122 * decide whether the filter succeeded or not
13123 */
13124 res = valuePop(ctxt);
13125 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13126 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013127 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013128 /*
13129 * Cleanup
13130 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013131 if (res != NULL) {
13132 xmlXPathReleaseObject(ctxt->context, res);
13133 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013134 if (ctxt->value == tmp) {
13135 valuePop(ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013136 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013137 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013138 * in order to avoid massive recreation inside this
13139 * loop.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013140 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000013141 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013142 } else
13143 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013144 ctxt->context->node = NULL;
13145 /*
13146 * Only put the first node in the result, then leave.
13147 */
13148 if (newset->nodeNr > 0) {
13149 *first = *(newset->nodeTab);
13150 break;
13151 }
13152 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013153 if (tmp != NULL) {
13154 xmlXPathReleaseObject(ctxt->context, tmp);
13155 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013156 /*
13157 * The result is used as the new evaluation set.
13158 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013159 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013160 ctxt->context->node = NULL;
13161 ctxt->context->contextSize = -1;
13162 ctxt->context->proximityPosition = -1;
13163 /* may want to move this past the '}' later */
13164 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013165 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013166 }
13167 ctxt->context->node = oldnode;
13168 return(total);
13169}
13170#endif /* XP_OPTIMIZED_FILTER_FIRST */
13171
Owen Taylor3473f882001-02-23 17:55:21 +000013172/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013173 * xmlXPathCompOpEval:
13174 * @ctxt: the XPath parser context with the compiled expression
13175 * @op: an XPath compiled operation
13176 *
13177 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000013178 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013179 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013180static int
13181xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13182{
13183 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013184 int equal, ret;
13185 xmlXPathCompExprPtr comp;
13186 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013187 xmlNodePtr bak;
13188 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000013189 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000013190 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013191
Daniel Veillard556c6682001-10-06 09:59:51 +000013192 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013193 comp = ctxt->comp;
13194 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013195 case XPATH_OP_END:
13196 return (0);
13197 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013198 bakd = ctxt->context->doc;
13199 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013200 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013201 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013202 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013203 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013204 xmlXPathBooleanFunction(ctxt, 1);
13205 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13206 return (total);
13207 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013208 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 Veillard556c6682001-10-06 09:59:51 +000013213 if (ctxt->error) {
13214 xmlXPathFreeObject(arg2);
13215 return(0);
13216 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013217 xmlXPathBooleanFunction(ctxt, 1);
13218 arg1 = valuePop(ctxt);
13219 arg1->boolval &= arg2->boolval;
13220 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013221 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013222 return (total);
13223 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013224 bakd = ctxt->context->doc;
13225 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013226 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013227 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013228 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013229 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013230 xmlXPathBooleanFunction(ctxt, 1);
13231 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13232 return (total);
13233 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013234 ctxt->context->doc = bakd;
13235 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013236 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013237 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013238 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013239 if (ctxt->error) {
13240 xmlXPathFreeObject(arg2);
13241 return(0);
13242 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013243 xmlXPathBooleanFunction(ctxt, 1);
13244 arg1 = valuePop(ctxt);
13245 arg1->boolval |= arg2->boolval;
13246 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013247 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013248 return (total);
13249 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013250 bakd = ctxt->context->doc;
13251 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013252 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013253 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013254 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013255 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013256 ctxt->context->doc = bakd;
13257 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013258 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013259 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013260 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013261 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000013262 if (op->value)
Daniel Veillard45490ae2008-07-29 09:13:19 +000013263 equal = xmlXPathEqualValues(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +000013264 else
13265 equal = xmlXPathNotEqualValues(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013266 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013267 return (total);
13268 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013269 bakd = ctxt->context->doc;
13270 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013271 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013272 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013273 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013274 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013275 ctxt->context->doc = bakd;
13276 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013277 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013278 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013279 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013280 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013281 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013282 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013283 return (total);
13284 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013285 bakd = ctxt->context->doc;
13286 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013287 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013288 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013289 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013290 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013291 if (op->ch2 != -1) {
13292 ctxt->context->doc = bakd;
13293 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013294 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013295 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013296 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013297 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013298 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013299 if (op->value == 0)
13300 xmlXPathSubValues(ctxt);
13301 else if (op->value == 1)
13302 xmlXPathAddValues(ctxt);
13303 else if (op->value == 2)
13304 xmlXPathValueFlipSign(ctxt);
13305 else if (op->value == 3) {
13306 CAST_TO_NUMBER;
13307 CHECK_TYPE0(XPATH_NUMBER);
13308 }
13309 return (total);
13310 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013311 bakd = ctxt->context->doc;
13312 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013313 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013314 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013315 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013316 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013317 ctxt->context->doc = bakd;
13318 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013319 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013320 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013321 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013322 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013323 if (op->value == 0)
13324 xmlXPathMultValues(ctxt);
13325 else if (op->value == 1)
13326 xmlXPathDivValues(ctxt);
13327 else if (op->value == 2)
13328 xmlXPathModValues(ctxt);
13329 return (total);
13330 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013331 bakd = ctxt->context->doc;
13332 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013333 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013334 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013335 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013336 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013337 ctxt->context->doc = bakd;
13338 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013339 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013340 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013341 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013342 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013343 CHECK_TYPE0(XPATH_NODESET);
13344 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013345
Daniel Veillardf06307e2001-07-03 10:35:50 +000013346 CHECK_TYPE0(XPATH_NODESET);
13347 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013348
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013349 if ((arg1->nodesetval == NULL) ||
13350 ((arg2->nodesetval != NULL) &&
13351 (arg2->nodesetval->nodeNr != 0)))
13352 {
13353 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13354 arg2->nodesetval);
13355 }
13356
Daniel Veillardf06307e2001-07-03 10:35:50 +000013357 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013358 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013359 return (total);
13360 case XPATH_OP_ROOT:
13361 xmlXPathRoot(ctxt);
13362 return (total);
13363 case XPATH_OP_NODE:
13364 if (op->ch1 != -1)
13365 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013366 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013367 if (op->ch2 != -1)
13368 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013369 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013370 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13371 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013372 return (total);
13373 case XPATH_OP_RESET:
13374 if (op->ch1 != -1)
13375 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013376 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013377 if (op->ch2 != -1)
13378 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013379 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013380 ctxt->context->node = NULL;
13381 return (total);
13382 case XPATH_OP_COLLECT:{
13383 if (op->ch1 == -1)
13384 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000013385
Daniel Veillardf06307e2001-07-03 10:35:50 +000013386 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013387 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013388
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013389 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013390 return (total);
13391 }
13392 case XPATH_OP_VALUE:
13393 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013394 xmlXPathCacheObjectCopy(ctxt->context,
13395 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013396 return (total);
13397 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000013398 xmlXPathObjectPtr val;
13399
Daniel Veillardf06307e2001-07-03 10:35:50 +000013400 if (op->ch1 != -1)
13401 total +=
13402 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013403 if (op->value5 == NULL) {
13404 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13405 if (val == NULL) {
13406 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13407 return(0);
13408 }
13409 valuePush(ctxt, val);
13410 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013411 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013412
Daniel Veillardf06307e2001-07-03 10:35:50 +000013413 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13414 if (URI == NULL) {
13415 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013416 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13417 (char *) op->value4, (char *)op->value5);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080013418 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013419 return (total);
13420 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013421 val = xmlXPathVariableLookupNS(ctxt->context,
13422 op->value4, URI);
13423 if (val == NULL) {
13424 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13425 return(0);
13426 }
13427 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013428 }
13429 return (total);
13430 }
13431 case XPATH_OP_FUNCTION:{
13432 xmlXPathFunction func;
13433 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000013434 int i;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013435 int frame;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013436
Daniel Veillardf5048b32011-08-18 17:10:13 +080013437 frame = xmlXPathSetFrame(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013438 if (op->ch1 != -1)
13439 total +=
13440 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013441 if (ctxt->valueNr < op->value) {
13442 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013443 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013444 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013445 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard556c6682001-10-06 09:59:51 +000013446 return (total);
13447 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080013448 for (i = 0; i < op->value; i++) {
Daniel Veillard556c6682001-10-06 09:59:51 +000013449 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13450 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013451 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013452 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013453 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard556c6682001-10-06 09:59:51 +000013454 return (total);
13455 }
Daniel Veillardf5048b32011-08-18 17:10:13 +080013456 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013457 if (op->cache != NULL)
William M. Brackad0e67c2004-12-01 14:35:10 +000013458 XML_CAST_FPTR(func) = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013459 else {
13460 const xmlChar *URI = NULL;
13461
13462 if (op->value5 == NULL)
13463 func =
13464 xmlXPathFunctionLookup(ctxt->context,
13465 op->value4);
13466 else {
13467 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13468 if (URI == NULL) {
13469 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013470 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13471 (char *)op->value4, (char *)op->value5);
Daniel Veillardf5048b32011-08-18 17:10:13 +080013472 xmlXPathPopFrame(ctxt, frame);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080013473 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013474 return (total);
13475 }
13476 func = xmlXPathFunctionLookupNS(ctxt->context,
13477 op->value4, URI);
13478 }
13479 if (func == NULL) {
13480 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf63085d2009-01-18 20:53:59 +000013481 "xmlXPathCompOpEval: function %s not found\n",
13482 (char *)op->value4);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013483 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013484 }
William M. Brackad0e67c2004-12-01 14:35:10 +000013485 op->cache = XML_CAST_FPTR(func);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013486 op->cacheURI = (void *) URI;
13487 }
13488 oldFunc = ctxt->context->function;
13489 oldFuncURI = ctxt->context->functionURI;
13490 ctxt->context->function = op->value4;
13491 ctxt->context->functionURI = op->cacheURI;
13492 func(ctxt, op->value);
13493 ctxt->context->function = oldFunc;
13494 ctxt->context->functionURI = oldFuncURI;
Daniel Veillardf5048b32011-08-18 17:10:13 +080013495 xmlXPathPopFrame(ctxt, frame);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013496 return (total);
13497 }
13498 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000013499 bakd = ctxt->context->doc;
13500 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000013501 pp = ctxt->context->proximityPosition;
13502 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013503 if (op->ch1 != -1)
13504 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
William M. Brack645a9242004-11-09 12:20:42 +000013505 ctxt->context->contextSize = cs;
13506 ctxt->context->proximityPosition = pp;
Daniel Veillard088bf112002-05-14 11:03:59 +000013507 ctxt->context->node = bak;
William M. Brack645a9242004-11-09 12:20:42 +000013508 ctxt->context->doc = bakd;
Daniel Veillard556c6682001-10-06 09:59:51 +000013509 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000013510 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013511 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000013512 ctxt->context->doc = bakd;
13513 ctxt->context->node = bak;
13514 CHECK_ERROR0;
13515 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013516 return (total);
13517 case XPATH_OP_PREDICATE:
13518 case XPATH_OP_FILTER:{
13519 xmlXPathObjectPtr res;
13520 xmlXPathObjectPtr obj, tmp;
13521 xmlNodeSetPtr newset = NULL;
13522 xmlNodeSetPtr oldset;
13523 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000013524 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013525 int i;
13526
13527 /*
13528 * Optimization for ()[1] selection i.e. the first elem
13529 */
13530 if ((op->ch1 != -1) && (op->ch2 != -1) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013531#ifdef XP_OPTIMIZED_FILTER_FIRST
13532 /*
13533 * FILTER TODO: Can we assume that the inner processing
13534 * will result in an ordered list if we have an
13535 * XPATH_OP_FILTER?
13536 * What about an additional field or flag on
13537 * xmlXPathObject like @sorted ? This way we wouln'd need
13538 * to assume anything, so it would be more robust and
13539 * easier to optimize.
13540 */
13541 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13542 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13543#else
13544 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13545#endif
13546 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013547 xmlXPathObjectPtr val;
13548
13549 val = comp->steps[op->ch2].value4;
13550 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13551 (val->floatval == 1.0)) {
13552 xmlNodePtr first = NULL;
13553
13554 total +=
13555 xmlXPathCompOpEvalFirst(ctxt,
13556 &comp->steps[op->ch1],
13557 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000013558 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013559 /*
13560 * The nodeset should be in document order,
13561 * Keep only the first value
13562 */
13563 if ((ctxt->value != NULL) &&
13564 (ctxt->value->type == XPATH_NODESET) &&
13565 (ctxt->value->nodesetval != NULL) &&
13566 (ctxt->value->nodesetval->nodeNr > 1))
13567 ctxt->value->nodesetval->nodeNr = 1;
13568 return (total);
13569 }
13570 }
13571 /*
13572 * Optimization for ()[last()] selection i.e. the last elem
13573 */
13574 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13575 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13576 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13577 int f = comp->steps[op->ch2].ch1;
13578
13579 if ((f != -1) &&
13580 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13581 (comp->steps[f].value5 == NULL) &&
13582 (comp->steps[f].value == 0) &&
13583 (comp->steps[f].value4 != NULL) &&
13584 (xmlStrEqual
13585 (comp->steps[f].value4, BAD_CAST "last"))) {
13586 xmlNodePtr last = NULL;
13587
13588 total +=
13589 xmlXPathCompOpEvalLast(ctxt,
13590 &comp->steps[op->ch1],
13591 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000013592 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013593 /*
13594 * The nodeset should be in document order,
13595 * Keep only the last value
13596 */
13597 if ((ctxt->value != NULL) &&
13598 (ctxt->value->type == XPATH_NODESET) &&
13599 (ctxt->value->nodesetval != NULL) &&
13600 (ctxt->value->nodesetval->nodeTab != NULL) &&
13601 (ctxt->value->nodesetval->nodeNr > 1)) {
13602 ctxt->value->nodesetval->nodeTab[0] =
13603 ctxt->value->nodesetval->nodeTab[ctxt->
13604 value->
13605 nodesetval->
13606 nodeNr -
13607 1];
13608 ctxt->value->nodesetval->nodeNr = 1;
13609 }
13610 return (total);
13611 }
13612 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013613 /*
13614 * Process inner predicates first.
13615 * Example "index[parent::book][1]":
13616 * ...
13617 * PREDICATE <-- we are here "[1]"
13618 * PREDICATE <-- process "[parent::book]" first
13619 * SORT
13620 * COLLECT 'parent' 'name' 'node' book
13621 * NODE
13622 * ELEM Object is a number : 1
13623 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013624 if (op->ch1 != -1)
13625 total +=
13626 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013627 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013628 if (op->ch2 == -1)
13629 return (total);
13630 if (ctxt->value == NULL)
13631 return (total);
13632
13633 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013634
13635#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013636 /*
13637 * Hum are we filtering the result of an XPointer expression
13638 */
13639 if (ctxt->value->type == XPATH_LOCATIONSET) {
13640 xmlLocationSetPtr newlocset = NULL;
13641 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013642
Daniel Veillardf06307e2001-07-03 10:35:50 +000013643 /*
13644 * Extract the old locset, and then evaluate the result of the
13645 * expression for all the element in the locset. use it to grow
13646 * up a new locset.
13647 */
13648 CHECK_TYPE0(XPATH_LOCATIONSET);
13649 obj = valuePop(ctxt);
13650 oldlocset = obj->user;
13651 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013652
Daniel Veillardf06307e2001-07-03 10:35:50 +000013653 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13654 ctxt->context->contextSize = 0;
13655 ctxt->context->proximityPosition = 0;
13656 if (op->ch2 != -1)
13657 total +=
13658 xmlXPathCompOpEval(ctxt,
13659 &comp->steps[op->ch2]);
13660 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013661 if (res != NULL) {
13662 xmlXPathReleaseObject(ctxt->context, res);
13663 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013664 valuePush(ctxt, obj);
13665 CHECK_ERROR0;
13666 return (total);
13667 }
13668 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013669
Daniel Veillardf06307e2001-07-03 10:35:50 +000013670 for (i = 0; i < oldlocset->locNr; i++) {
13671 /*
13672 * Run the evaluation with a node list made of a
13673 * single item in the nodelocset.
13674 */
13675 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013676 ctxt->context->contextSize = oldlocset->locNr;
13677 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013678 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13679 ctxt->context->node);
William M. Brackf7eb7942003-12-31 07:59:17 +000013680 valuePush(ctxt, tmp);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013681
Daniel Veillardf06307e2001-07-03 10:35:50 +000013682 if (op->ch2 != -1)
13683 total +=
13684 xmlXPathCompOpEval(ctxt,
13685 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013686 if (ctxt->error != XPATH_EXPRESSION_OK) {
13687 xmlXPathFreeObject(obj);
13688 return(0);
13689 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013690
Daniel Veillardf06307e2001-07-03 10:35:50 +000013691 /*
13692 * The result of the evaluation need to be tested to
13693 * decided whether the filter succeeded or not
13694 */
13695 res = valuePop(ctxt);
13696 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13697 xmlXPtrLocationSetAdd(newlocset,
13698 xmlXPathObjectCopy
13699 (oldlocset->locTab[i]));
13700 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013701
Daniel Veillardf06307e2001-07-03 10:35:50 +000013702 /*
13703 * Cleanup
13704 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013705 if (res != NULL) {
13706 xmlXPathReleaseObject(ctxt->context, res);
13707 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013708 if (ctxt->value == tmp) {
13709 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013710 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013711 }
13712
13713 ctxt->context->node = NULL;
13714 }
13715
13716 /*
13717 * The result is used as the new evaluation locset.
13718 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013719 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013720 ctxt->context->node = NULL;
13721 ctxt->context->contextSize = -1;
13722 ctxt->context->proximityPosition = -1;
13723 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13724 ctxt->context->node = oldnode;
13725 return (total);
13726 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013727#endif /* LIBXML_XPTR_ENABLED */
13728
Daniel Veillardf06307e2001-07-03 10:35:50 +000013729 /*
13730 * Extract the old set, and then evaluate the result of the
13731 * expression for all the element in the set. use it to grow
13732 * up a new set.
13733 */
13734 CHECK_TYPE0(XPATH_NODESET);
13735 obj = valuePop(ctxt);
13736 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000013737
Daniel Veillardf06307e2001-07-03 10:35:50 +000013738 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000013739 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013740 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013741
Daniel Veillardf06307e2001-07-03 10:35:50 +000013742 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13743 ctxt->context->contextSize = 0;
13744 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000013745/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000013746 if (op->ch2 != -1)
13747 total +=
13748 xmlXPathCompOpEval(ctxt,
13749 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013750 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013751 res = valuePop(ctxt);
13752 if (res != NULL)
13753 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000013754*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000013755 valuePush(ctxt, obj);
13756 ctxt->context->node = oldnode;
13757 CHECK_ERROR0;
13758 } else {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013759 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013760 /*
13761 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000013762 * Also set the xpath document in case things like
13763 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000013764 */
13765 newset = xmlXPathNodeSetCreate(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013766 /*
13767 * SPEC XPath 1.0:
13768 * "For each node in the node-set to be filtered, the
13769 * PredicateExpr is evaluated with that node as the
13770 * context node, with the number of nodes in the
13771 * node-set as the context size, and with the proximity
13772 * position of the node in the node-set with respect to
13773 * the axis as the context position;"
13774 * @oldset is the node-set" to be filtered.
13775 *
13776 * SPEC XPath 1.0:
13777 * "only predicates change the context position and
13778 * context size (see [2.4 Predicates])."
13779 * Example:
13780 * node-set context pos
13781 * nA 1
13782 * nB 2
13783 * nC 3
13784 * After applying predicate [position() > 1] :
13785 * node-set context pos
13786 * nB 1
13787 * nC 2
13788 *
13789 * removed the first node in the node-set, then
Daniel Veillard45490ae2008-07-29 09:13:19 +000013790 * the context position of the
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013791 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013792 for (i = 0; i < oldset->nodeNr; i++) {
13793 /*
13794 * Run the evaluation with a node list made of
13795 * a single item in the nodeset.
13796 */
13797 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000013798 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13799 (oldset->nodeTab[i]->doc != NULL))
13800 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013801 if (tmp == NULL) {
13802 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13803 ctxt->context->node);
13804 } else {
13805 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13806 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013807 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013808 valuePush(ctxt, tmp);
13809 ctxt->context->contextSize = oldset->nodeNr;
13810 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013811 /*
13812 * Evaluate the predicate against the context node.
13813 * Can/should we optimize position() predicates
13814 * here (e.g. "[1]")?
13815 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013816 if (op->ch2 != -1)
13817 total +=
13818 xmlXPathCompOpEval(ctxt,
13819 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013820 if (ctxt->error != XPATH_EXPRESSION_OK) {
13821 xmlXPathFreeNodeSet(newset);
13822 xmlXPathFreeObject(obj);
13823 return(0);
13824 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013825
Daniel Veillardf06307e2001-07-03 10:35:50 +000013826 /*
William M. Brack08171912003-12-29 02:52:11 +000013827 * The result of the evaluation needs to be tested to
13828 * decide whether the filter succeeded or not
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013829 */
13830 /*
13831 * OPTIMIZE TODO: Can we use
13832 * xmlXPathNodeSetAdd*Unique()* instead?
13833 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013834 res = valuePop(ctxt);
13835 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13836 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13837 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013838
Daniel Veillardf06307e2001-07-03 10:35:50 +000013839 /*
13840 * Cleanup
13841 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013842 if (res != NULL) {
13843 xmlXPathReleaseObject(ctxt->context, res);
13844 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013845 if (ctxt->value == tmp) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013846 valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000013847 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013848 /*
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013849 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013850 * in order to avoid massive recreation inside this
13851 * loop.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013852 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013853 } else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013854 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013855 ctxt->context->node = NULL;
13856 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013857 if (tmp != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013858 xmlXPathReleaseObject(ctxt->context, tmp);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013859 /*
13860 * The result is used as the new evaluation set.
13861 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013862 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013863 ctxt->context->node = NULL;
13864 ctxt->context->contextSize = -1;
13865 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000013866 /* may want to move this past the '}' later */
13867 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013868 valuePush(ctxt,
13869 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013870 }
13871 ctxt->context->node = oldnode;
13872 return (total);
13873 }
13874 case XPATH_OP_SORT:
13875 if (op->ch1 != -1)
13876 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013877 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013878 if ((ctxt->value != NULL) &&
13879 (ctxt->value->type == XPATH_NODESET) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013880 (ctxt->value->nodesetval != NULL) &&
13881 (ctxt->value->nodesetval->nodeNr > 1))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013882 {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013883 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013884 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013885 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013886#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013887 case XPATH_OP_RANGETO:{
13888 xmlXPathObjectPtr range;
13889 xmlXPathObjectPtr res, obj;
13890 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000013891 xmlLocationSetPtr newlocset = NULL;
13892 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013893 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000013894 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013895
Daniel Veillardf06307e2001-07-03 10:35:50 +000013896 if (op->ch1 != -1)
13897 total +=
13898 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13899 if (op->ch2 == -1)
13900 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013901
William M. Brack08171912003-12-29 02:52:11 +000013902 if (ctxt->value->type == XPATH_LOCATIONSET) {
13903 /*
13904 * Extract the old locset, and then evaluate the result of the
13905 * expression for all the element in the locset. use it to grow
13906 * up a new locset.
13907 */
13908 CHECK_TYPE0(XPATH_LOCATIONSET);
13909 obj = valuePop(ctxt);
13910 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013911
William M. Brack08171912003-12-29 02:52:11 +000013912 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000013913 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000013914 ctxt->context->contextSize = 0;
13915 ctxt->context->proximityPosition = 0;
13916 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13917 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013918 if (res != NULL) {
13919 xmlXPathReleaseObject(ctxt->context, res);
13920 }
William M. Brack08171912003-12-29 02:52:11 +000013921 valuePush(ctxt, obj);
13922 CHECK_ERROR0;
13923 return (total);
13924 }
13925 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013926
William M. Brack08171912003-12-29 02:52:11 +000013927 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013928 /*
William M. Brack08171912003-12-29 02:52:11 +000013929 * Run the evaluation with a node list made of a
13930 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000013931 */
William M. Brackf7eb7942003-12-31 07:59:17 +000013932 ctxt->context->node = oldlocset->locTab[i]->user;
13933 ctxt->context->contextSize = oldlocset->locNr;
13934 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013935 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13936 ctxt->context->node);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013937 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013938
Daniel Veillardf06307e2001-07-03 10:35:50 +000013939 if (op->ch2 != -1)
13940 total +=
13941 xmlXPathCompOpEval(ctxt,
13942 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013943 if (ctxt->error != XPATH_EXPRESSION_OK) {
13944 xmlXPathFreeObject(obj);
13945 return(0);
13946 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013947
Daniel Veillardf06307e2001-07-03 10:35:50 +000013948 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000013949 if (res->type == XPATH_LOCATIONSET) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000013950 xmlLocationSetPtr rloc =
William M. Brack72ee48d2003-12-30 08:30:19 +000013951 (xmlLocationSetPtr)res->user;
13952 for (j=0; j<rloc->locNr; j++) {
13953 range = xmlXPtrNewRange(
13954 oldlocset->locTab[i]->user,
13955 oldlocset->locTab[i]->index,
13956 rloc->locTab[j]->user2,
13957 rloc->locTab[j]->index2);
13958 if (range != NULL) {
13959 xmlXPtrLocationSetAdd(newlocset, range);
13960 }
13961 }
13962 } else {
13963 range = xmlXPtrNewRangeNodeObject(
13964 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13965 if (range != NULL) {
13966 xmlXPtrLocationSetAdd(newlocset,range);
13967 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013968 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013969
Daniel Veillardf06307e2001-07-03 10:35:50 +000013970 /*
13971 * Cleanup
13972 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013973 if (res != NULL) {
13974 xmlXPathReleaseObject(ctxt->context, res);
13975 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013976 if (ctxt->value == tmp) {
13977 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013978 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013979 }
13980
13981 ctxt->context->node = NULL;
13982 }
William M. Brack72ee48d2003-12-30 08:30:19 +000013983 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000013984 CHECK_TYPE0(XPATH_NODESET);
13985 obj = valuePop(ctxt);
13986 oldset = obj->nodesetval;
13987 ctxt->context->node = NULL;
13988
13989 newlocset = xmlXPtrLocationSetCreate(NULL);
13990
13991 if (oldset != NULL) {
13992 for (i = 0; i < oldset->nodeNr; i++) {
13993 /*
13994 * Run the evaluation with a node list made of a single item
13995 * in the nodeset.
13996 */
13997 ctxt->context->node = oldset->nodeTab[i];
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013998 /*
13999 * OPTIMIZE TODO: Avoid recreation for every iteration.
14000 */
14001 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14002 ctxt->context->node);
William M. Brack08171912003-12-29 02:52:11 +000014003 valuePush(ctxt, tmp);
14004
14005 if (op->ch2 != -1)
14006 total +=
14007 xmlXPathCompOpEval(ctxt,
14008 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000014009 if (ctxt->error != XPATH_EXPRESSION_OK) {
14010 xmlXPathFreeObject(obj);
14011 return(0);
14012 }
William M. Brack08171912003-12-29 02:52:11 +000014013
William M. Brack08171912003-12-29 02:52:11 +000014014 res = valuePop(ctxt);
14015 range =
14016 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
14017 res);
14018 if (range != NULL) {
14019 xmlXPtrLocationSetAdd(newlocset, range);
14020 }
14021
14022 /*
14023 * Cleanup
14024 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014025 if (res != NULL) {
14026 xmlXPathReleaseObject(ctxt->context, res);
14027 }
William M. Brack08171912003-12-29 02:52:11 +000014028 if (ctxt->value == tmp) {
14029 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014030 xmlXPathReleaseObject(ctxt->context, res);
William M. Brack08171912003-12-29 02:52:11 +000014031 }
14032
14033 ctxt->context->node = NULL;
14034 }
14035 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014036 }
14037
14038 /*
14039 * The result is used as the new evaluation set.
14040 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014041 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000014042 ctxt->context->node = NULL;
14043 ctxt->context->contextSize = -1;
14044 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000014045 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000014046 return (total);
14047 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014048#endif /* LIBXML_XPTR_ENABLED */
14049 }
14050 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000014051 "XPath: unknown precompiled operation %d\n", op->op);
Daniel Veillard1d4526f2011-10-11 16:34:34 +080014052 ctxt->error = XPATH_INVALID_OPERAND;
Daniel Veillardf06307e2001-07-03 10:35:50 +000014053 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014054}
14055
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014056/**
14057 * xmlXPathCompOpEvalToBoolean:
14058 * @ctxt: the XPath parser context
14059 *
14060 * Evaluates if the expression evaluates to true.
14061 *
14062 * Returns 1 if true, 0 if false and -1 on API or internal errors.
14063 */
14064static int
14065xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014066 xmlXPathStepOpPtr op,
14067 int isPredicate)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014068{
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014069 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014070
14071start:
14072 /* comp = ctxt->comp; */
14073 switch (op->op) {
14074 case XPATH_OP_END:
14075 return (0);
14076 case XPATH_OP_VALUE:
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014077 resObj = (xmlXPathObjectPtr) op->value4;
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000014078 if (isPredicate)
14079 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14080 return(xmlXPathCastToBoolean(resObj));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014081 case XPATH_OP_SORT:
14082 /*
14083 * We don't need sorting for boolean results. Skip this one.
14084 */
14085 if (op->ch1 != -1) {
14086 op = &ctxt->comp->steps[op->ch1];
14087 goto start;
14088 }
14089 return(0);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014090 case XPATH_OP_COLLECT:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014091 if (op->ch1 == -1)
14092 return(0);
14093
14094 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14095 if (ctxt->error != XPATH_EXPRESSION_OK)
14096 return(-1);
14097
14098 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14099 if (ctxt->error != XPATH_EXPRESSION_OK)
14100 return(-1);
14101
14102 resObj = valuePop(ctxt);
14103 if (resObj == NULL)
14104 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014105 break;
14106 default:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014107 /*
14108 * Fallback to call xmlXPathCompOpEval().
14109 */
14110 xmlXPathCompOpEval(ctxt, op);
14111 if (ctxt->error != XPATH_EXPRESSION_OK)
14112 return(-1);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014113
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014114 resObj = valuePop(ctxt);
14115 if (resObj == NULL)
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000014116 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014117 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014118 }
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014119
14120 if (resObj) {
14121 int res;
14122
14123 if (resObj->type == XPATH_BOOLEAN) {
14124 res = resObj->boolval;
14125 } else if (isPredicate) {
14126 /*
14127 * For predicates a result of type "number" is handled
14128 * differently:
14129 * SPEC XPath 1.0:
14130 * "If the result is a number, the result will be converted
14131 * to true if the number is equal to the context position
14132 * and will be converted to false otherwise;"
14133 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000014134 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014135 } else {
14136 res = xmlXPathCastToBoolean(resObj);
14137 }
14138 xmlXPathReleaseObject(ctxt->context, resObj);
14139 return(res);
14140 }
14141
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014142 return(0);
14143}
14144
Daniel Veillard56de87e2005-02-16 00:22:29 +000014145#ifdef XPATH_STREAMING
14146/**
14147 * xmlXPathRunStreamEval:
14148 * @ctxt: the XPath parser context with the compiled expression
14149 *
14150 * Evaluate the Precompiled Streamable XPath expression in the given context.
14151 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014152static int
14153xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14154 xmlXPathObjectPtr *resultSeq, int toBool)
14155{
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014156 int max_depth, min_depth;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014157 int from_root;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014158 int ret, depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014159 int eval_all_nodes;
William M. Brack12d37ab2005-02-21 13:54:07 +000014160 xmlNodePtr cur = NULL, limit = NULL;
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014161 xmlStreamCtxtPtr patstream = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014162
14163 int nb_nodes = 0;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014164
14165 if ((ctxt == NULL) || (comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014166 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014167 max_depth = xmlPatternMaxDepth(comp);
14168 if (max_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014169 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014170 if (max_depth == -2)
14171 max_depth = 10000;
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014172 min_depth = xmlPatternMinDepth(comp);
14173 if (min_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014174 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014175 from_root = xmlPatternFromRoot(comp);
14176 if (from_root < 0)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014177 return(-1);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014178#if 0
14179 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14180#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000014181
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014182 if (! toBool) {
14183 if (resultSeq == NULL)
14184 return(-1);
14185 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14186 if (*resultSeq == NULL)
14187 return(-1);
14188 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014189
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014190 /*
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014191 * handle the special cases of "/" amd "." being matched
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014192 */
14193 if (min_depth == 0) {
14194 if (from_root) {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014195 /* Select "/" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014196 if (toBool)
14197 return(1);
14198 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14199 (xmlNodePtr) ctxt->doc);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014200 } else {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014201 /* Select "self::node()" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014202 if (toBool)
14203 return(1);
14204 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014205 }
14206 }
14207 if (max_depth == 0) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014208 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014209 }
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014210
Daniel Veillard56de87e2005-02-16 00:22:29 +000014211 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000014212 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014213 } else if (ctxt->node != NULL) {
14214 switch (ctxt->node->type) {
14215 case XML_ELEMENT_NODE:
14216 case XML_DOCUMENT_NODE:
14217 case XML_DOCUMENT_FRAG_NODE:
14218 case XML_HTML_DOCUMENT_NODE:
14219#ifdef LIBXML_DOCB_ENABLED
14220 case XML_DOCB_DOCUMENT_NODE:
14221#endif
14222 cur = ctxt->node;
14223 break;
14224 case XML_ATTRIBUTE_NODE:
14225 case XML_TEXT_NODE:
14226 case XML_CDATA_SECTION_NODE:
14227 case XML_ENTITY_REF_NODE:
14228 case XML_ENTITY_NODE:
14229 case XML_PI_NODE:
14230 case XML_COMMENT_NODE:
14231 case XML_NOTATION_NODE:
14232 case XML_DTD_NODE:
14233 case XML_DOCUMENT_TYPE_NODE:
14234 case XML_ELEMENT_DECL:
14235 case XML_ATTRIBUTE_DECL:
14236 case XML_ENTITY_DECL:
14237 case XML_NAMESPACE_DECL:
14238 case XML_XINCLUDE_START:
14239 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000014240 break;
14241 }
14242 limit = cur;
14243 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014244 if (cur == NULL) {
14245 return(0);
14246 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014247
14248 patstream = xmlPatternGetStreamCtxt(comp);
14249 if (patstream == NULL) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014250 /*
14251 * QUESTION TODO: Is this an error?
14252 */
14253 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014254 }
14255
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014256 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014257
Daniel Veillard56de87e2005-02-16 00:22:29 +000014258 if (from_root) {
14259 ret = xmlStreamPush(patstream, NULL, NULL);
14260 if (ret < 0) {
14261 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014262 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014263 goto return_1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014264 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014265 }
14266 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014267 depth = 0;
14268 goto scan_children;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014269next_node:
Daniel Veillardd3ff7ef2006-02-27 19:43:17 +000014270 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014271 nb_nodes++;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014272
14273 switch (cur->type) {
14274 case XML_ELEMENT_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014275 case XML_TEXT_NODE:
14276 case XML_CDATA_SECTION_NODE:
14277 case XML_COMMENT_NODE:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014278 case XML_PI_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014279 if (cur->type == XML_ELEMENT_NODE) {
14280 ret = xmlStreamPush(patstream, cur->name,
Daniel Veillard56de87e2005-02-16 00:22:29 +000014281 (cur->ns ? cur->ns->href : NULL));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014282 } else if (eval_all_nodes)
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014283 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14284 else
14285 break;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014286
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014287 if (ret < 0) {
14288 /* NOP. */
14289 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014290 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014291 goto return_1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014292 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014293 }
14294 if ((cur->children == NULL) || (depth >= max_depth)) {
14295 ret = xmlStreamPop(patstream);
14296 while (cur->next != NULL) {
14297 cur = cur->next;
14298 if ((cur->type != XML_ENTITY_DECL) &&
14299 (cur->type != XML_DTD_NODE))
14300 goto next_node;
14301 }
14302 }
14303 default:
14304 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014305 }
14306
Daniel Veillard56de87e2005-02-16 00:22:29 +000014307scan_children:
14308 if ((cur->children != NULL) && (depth < max_depth)) {
14309 /*
Daniel Veillard45490ae2008-07-29 09:13:19 +000014310 * Do not descend on entities declarations
Daniel Veillard56de87e2005-02-16 00:22:29 +000014311 */
14312 if (cur->children->type != XML_ENTITY_DECL) {
14313 cur = cur->children;
14314 depth++;
14315 /*
14316 * Skip DTDs
14317 */
14318 if (cur->type != XML_DTD_NODE)
14319 continue;
14320 }
14321 }
14322
14323 if (cur == limit)
14324 break;
14325
14326 while (cur->next != NULL) {
14327 cur = cur->next;
14328 if ((cur->type != XML_ENTITY_DECL) &&
14329 (cur->type != XML_DTD_NODE))
14330 goto next_node;
14331 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014332
Daniel Veillard56de87e2005-02-16 00:22:29 +000014333 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014334 cur = cur->parent;
14335 depth--;
14336 if ((cur == NULL) || (cur == limit))
14337 goto done;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014338 if (cur->type == XML_ELEMENT_NODE) {
14339 ret = xmlStreamPop(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014340 } else if ((eval_all_nodes) &&
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014341 ((cur->type == XML_TEXT_NODE) ||
14342 (cur->type == XML_CDATA_SECTION_NODE) ||
14343 (cur->type == XML_COMMENT_NODE) ||
14344 (cur->type == XML_PI_NODE)))
14345 {
14346 ret = xmlStreamPop(patstream);
14347 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014348 if (cur->next != NULL) {
14349 cur = cur->next;
14350 break;
14351 }
14352 } while (cur != NULL);
14353
14354 } while ((cur != NULL) && (depth >= 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014355
Daniel Veillard56de87e2005-02-16 00:22:29 +000014356done:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014357
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014358#if 0
14359 printf("stream eval: checked %d nodes selected %d\n",
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014360 nb_nodes, retObj->nodesetval->nodeNr);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014361#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014362
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014363 if (patstream)
14364 xmlFreeStreamCtxt(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014365 return(0);
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014366
14367return_1:
14368 if (patstream)
14369 xmlFreeStreamCtxt(patstream);
14370 return(1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014371}
14372#endif /* XPATH_STREAMING */
14373
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014374/**
14375 * xmlXPathRunEval:
14376 * @ctxt: the XPath parser context with the compiled expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014377 * @toBool: evaluate to a boolean result
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014378 *
14379 * Evaluate the Precompiled XPath expression in the given context.
14380 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014381static int
14382xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14383{
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014384 xmlXPathCompExprPtr comp;
14385
14386 if ((ctxt == NULL) || (ctxt->comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014387 return(-1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014388
14389 if (ctxt->valueTab == NULL) {
14390 /* Allocate the value stack */
Daniel Veillard45490ae2008-07-29 09:13:19 +000014391 ctxt->valueTab = (xmlXPathObjectPtr *)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014392 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14393 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000014394 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014395 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014396 }
14397 ctxt->valueNr = 0;
14398 ctxt->valueMax = 10;
14399 ctxt->value = NULL;
Daniel Veillardf5048b32011-08-18 17:10:13 +080014400 ctxt->valueFrame = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014401 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014402#ifdef XPATH_STREAMING
14403 if (ctxt->comp->stream) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014404 int res;
14405
14406 if (toBool) {
14407 /*
14408 * Evaluation to boolean result.
14409 */
14410 res = xmlXPathRunStreamEval(ctxt->context,
14411 ctxt->comp->stream, NULL, 1);
14412 if (res != -1)
14413 return(res);
14414 } else {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014415 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014416
14417 /*
14418 * Evaluation to a sequence.
14419 */
14420 res = xmlXPathRunStreamEval(ctxt->context,
14421 ctxt->comp->stream, &resObj, 0);
14422
14423 if ((res != -1) && (resObj != NULL)) {
14424 valuePush(ctxt, resObj);
14425 return(0);
14426 }
14427 if (resObj != NULL)
Daniel Veillard45490ae2008-07-29 09:13:19 +000014428 xmlXPathReleaseObject(ctxt->context, resObj);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014429 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014430 /*
14431 * QUESTION TODO: This falls back to normal XPath evaluation
14432 * if res == -1. Is this intended?
14433 */
Daniel Veillard56de87e2005-02-16 00:22:29 +000014434 }
14435#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014436 comp = ctxt->comp;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014437 if (comp->last < 0) {
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014438 xmlGenericError(xmlGenericErrorContext,
14439 "xmlXPathRunEval: last is less than zero\n");
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014440 return(-1);
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014441 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014442 if (toBool)
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014443 return(xmlXPathCompOpEvalToBoolean(ctxt,
14444 &comp->steps[comp->last], 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014445 else
14446 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14447
14448 return(0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014449}
14450
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014451/************************************************************************
14452 * *
Daniel Veillard45490ae2008-07-29 09:13:19 +000014453 * Public interfaces *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014454 * *
14455 ************************************************************************/
14456
14457/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014458 * xmlXPathEvalPredicate:
14459 * @ctxt: the XPath context
14460 * @res: the Predicate Expression evaluation result
14461 *
14462 * Evaluate a predicate result for the current node.
14463 * A PredicateExpr is evaluated by evaluating the Expr and converting
14464 * the result to a boolean. If the result is a number, the result will
14465 * be converted to true if the number is equal to the position of the
14466 * context node in the context node list (as returned by the position
14467 * function) and will be converted to false otherwise; if the result
14468 * is not a number, then the result will be converted as if by a call
Daniel Veillard45490ae2008-07-29 09:13:19 +000014469 * to the boolean function.
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014470 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014471 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014472 */
14473int
14474xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014475 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014476 switch (res->type) {
14477 case XPATH_BOOLEAN:
14478 return(res->boolval);
14479 case XPATH_NUMBER:
14480 return(res->floatval == ctxt->proximityPosition);
14481 case XPATH_NODESET:
14482 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000014483 if (res->nodesetval == NULL)
14484 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014485 return(res->nodesetval->nodeNr != 0);
14486 case XPATH_STRING:
14487 return((res->stringval != NULL) &&
14488 (xmlStrlen(res->stringval) != 0));
14489 default:
14490 STRANGE
14491 }
14492 return(0);
14493}
14494
14495/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014496 * xmlXPathEvaluatePredicateResult:
14497 * @ctxt: the XPath Parser context
14498 * @res: the Predicate Expression evaluation result
14499 *
14500 * Evaluate a predicate result for the current node.
14501 * A PredicateExpr is evaluated by evaluating the Expr and converting
14502 * the result to a boolean. If the result is a number, the result will
14503 * be converted to true if the number is equal to the position of the
14504 * context node in the context node list (as returned by the position
14505 * function) and will be converted to false otherwise; if the result
14506 * is not a number, then the result will be converted as if by a call
Daniel Veillard45490ae2008-07-29 09:13:19 +000014507 * to the boolean function.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014508 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014509 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014510 */
14511int
Daniel Veillard45490ae2008-07-29 09:13:19 +000014512xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014513 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014514 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014515 switch (res->type) {
14516 case XPATH_BOOLEAN:
14517 return(res->boolval);
14518 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000014519#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000014520 return((res->floatval == ctxt->context->proximityPosition) &&
14521 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000014522#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014523 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000014524#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014525 case XPATH_NODESET:
14526 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000014527 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000014528 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014529 return(res->nodesetval->nodeNr != 0);
14530 case XPATH_STRING:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014531 return((res->stringval != NULL) && (res->stringval[0] != 0));
William M. Brack08171912003-12-29 02:52:11 +000014532#ifdef LIBXML_XPTR_ENABLED
14533 case XPATH_LOCATIONSET:{
14534 xmlLocationSetPtr ptr = res->user;
14535 if (ptr == NULL)
14536 return(0);
14537 return (ptr->locNr != 0);
14538 }
14539#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014540 default:
14541 STRANGE
14542 }
14543 return(0);
14544}
14545
Daniel Veillard56de87e2005-02-16 00:22:29 +000014546#ifdef XPATH_STREAMING
14547/**
14548 * xmlXPathTryStreamCompile:
14549 * @ctxt: an XPath context
14550 * @str: the XPath expression
14551 *
14552 * Try to compile the XPath expression as a streamable subset.
14553 *
14554 * Returns the compiled expression or NULL if failed to compile.
14555 */
14556static xmlXPathCompExprPtr
14557xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14558 /*
14559 * Optimization: use streaming patterns when the XPath expression can
14560 * be compiled to a stream lookup
14561 */
14562 xmlPatternPtr stream;
14563 xmlXPathCompExprPtr comp;
14564 xmlDictPtr dict = NULL;
14565 const xmlChar **namespaces = NULL;
14566 xmlNsPtr ns;
14567 int i, j;
14568
14569 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14570 (!xmlStrchr(str, '@'))) {
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014571 const xmlChar *tmp;
14572
14573 /*
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014574 * We don't try to handle expressions using the verbose axis
14575 * specifiers ("::"), just the simplied form at this point.
14576 * Additionally, if there is no list of namespaces available and
14577 * there's a ":" in the expression, indicating a prefixed QName,
14578 * then we won't try to compile either. xmlPatterncompile() needs
14579 * to have a list of namespaces at compilation time in order to
14580 * compile prefixed name tests.
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014581 */
14582 tmp = xmlStrchr(str, ':');
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014583 if ((tmp != NULL) &&
14584 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
Daniel Veillard45490ae2008-07-29 09:13:19 +000014585 return(NULL);
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014586
Daniel Veillard56de87e2005-02-16 00:22:29 +000014587 if (ctxt != NULL) {
14588 dict = ctxt->dict;
14589 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000014590 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000014591 if (namespaces == NULL) {
14592 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14593 return(NULL);
14594 }
14595 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14596 ns = ctxt->namespaces[j];
14597 namespaces[i++] = ns->href;
14598 namespaces[i++] = ns->prefix;
14599 }
14600 namespaces[i++] = NULL;
Daniel Veillard13cee4e2009-09-05 14:52:55 +020014601 namespaces[i] = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014602 }
14603 }
14604
William M. Brackea152c02005-06-09 18:12:28 +000014605 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14606 &namespaces[0]);
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014607 if (namespaces != NULL) {
14608 xmlFree((xmlChar **)namespaces);
Daniel Veillard45490ae2008-07-29 09:13:19 +000014609 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014610 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14611 comp = xmlXPathNewCompExpr();
14612 if (comp == NULL) {
14613 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14614 return(NULL);
14615 }
14616 comp->stream = stream;
14617 comp->dict = dict;
14618 if (comp->dict)
14619 xmlDictReference(comp->dict);
14620 return(comp);
14621 }
14622 xmlFreePattern(stream);
14623 }
14624 return(NULL);
14625}
14626#endif /* XPATH_STREAMING */
14627
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014628static int
14629xmlXPathCanRewriteDosExpression(xmlChar *expr)
14630{
14631 if (expr == NULL)
14632 return(0);
14633 do {
14634 if ((*expr == '/') && (*(++expr) == '/'))
14635 return(1);
14636 } while (*expr++);
14637 return(0);
14638}
14639static void
14640xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14641{
14642 /*
14643 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14644 * internal representation.
14645 */
14646 if (op->ch1 != -1) {
14647 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +000014648 ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014649 ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
14650 ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
14651 {
14652 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014653 * This is a "child::foo"
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014654 */
Daniel Veillard45490ae2008-07-29 09:13:19 +000014655 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014656
14657 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
Daniel Veillard45490ae2008-07-29 09:13:19 +000014658 (prevop->ch1 != -1) &&
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014659 ((xmlXPathAxisVal) prevop->value ==
14660 AXIS_DESCENDANT_OR_SELF) &&
14661 (prevop->ch2 == -1) &&
14662 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014663 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
14664 (comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
Daniel Veillard45490ae2008-07-29 09:13:19 +000014665 {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014666 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014667 * This is a "/descendant-or-self::node()" without predicates.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014668 * Eliminate it.
14669 */
14670 op->ch1 = prevop->ch1;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014671 op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014672 }
14673 }
14674 if (op->ch1 != -1)
14675 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
14676 }
14677 if (op->ch2 != -1)
14678 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
14679}
14680
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014681/**
Daniel Veillard4773df22004-01-23 13:15:13 +000014682 * xmlXPathCtxtCompile:
14683 * @ctxt: an XPath context
14684 * @str: the XPath expression
14685 *
14686 * Compile an XPath expression
14687 *
14688 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14689 * the caller has to free the object.
14690 */
14691xmlXPathCompExprPtr
14692xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14693 xmlXPathParserContextPtr pctxt;
14694 xmlXPathCompExprPtr comp;
14695
Daniel Veillard56de87e2005-02-16 00:22:29 +000014696#ifdef XPATH_STREAMING
14697 comp = xmlXPathTryStreamCompile(ctxt, str);
14698 if (comp != NULL)
14699 return(comp);
14700#endif
14701
Daniel Veillard4773df22004-01-23 13:15:13 +000014702 xmlXPathInit();
14703
14704 pctxt = xmlXPathNewParserContext(str, ctxt);
William M. Brack11be2d02007-01-24 19:17:19 +000014705 if (pctxt == NULL)
14706 return NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014707 xmlXPathCompileExpr(pctxt, 1);
Daniel Veillard4773df22004-01-23 13:15:13 +000014708
14709 if( pctxt->error != XPATH_EXPRESSION_OK )
14710 {
14711 xmlXPathFreeParserContext(pctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000014712 return(NULL);
Daniel Veillard4773df22004-01-23 13:15:13 +000014713 }
14714
14715 if (*pctxt->cur != 0) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014716 /*
Daniel Veillard4773df22004-01-23 13:15:13 +000014717 * aleksey: in some cases this line prints *second* error message
14718 * (see bug #78858) and probably this should be fixed.
14719 * However, we are not sure that all error messages are printed
14720 * out in other places. It's not critical so we leave it as-is for now
14721 */
14722 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14723 comp = NULL;
14724 } else {
14725 comp = pctxt->comp;
14726 pctxt->comp = NULL;
14727 }
14728 xmlXPathFreeParserContext(pctxt);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014729
Daniel Veillard4773df22004-01-23 13:15:13 +000014730 if (comp != NULL) {
14731 comp->expr = xmlStrdup(str);
14732#ifdef DEBUG_EVAL_COUNTS
14733 comp->string = xmlStrdup(str);
14734 comp->nb = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014735#endif
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014736 if ((comp->expr != NULL) &&
14737 (comp->nbStep > 2) &&
14738 (comp->last >= 0) &&
Kasimier T. Buchcik7cb3fa92006-06-06 15:27:46 +000014739 (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
14740 {
14741 xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014742 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014743 }
Daniel Veillard4773df22004-01-23 13:15:13 +000014744 return(comp);
14745}
14746
14747/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014748 * xmlXPathCompile:
14749 * @str: the XPath expression
14750 *
14751 * Compile an XPath expression
14752 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000014753 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014754 * the caller has to free the object.
14755 */
14756xmlXPathCompExprPtr
14757xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000014758 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014759}
14760
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014761/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014762 * xmlXPathCompiledEvalInternal:
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014763 * @comp: the compiled XPath expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014764 * @ctxt: the XPath context
14765 * @resObj: the resulting XPath object or NULL
14766 * @toBool: 1 if only a boolean result is requested
Owen Taylor3473f882001-02-23 17:55:21 +000014767 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014768 * Evaluate the Precompiled XPath expression in the given context.
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014769 * The caller has to free @resObj.
Owen Taylor3473f882001-02-23 17:55:21 +000014770 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014771 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000014772 * the caller has to free the object.
14773 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014774static int
14775xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14776 xmlXPathContextPtr ctxt,
14777 xmlXPathObjectPtr *resObj,
14778 int toBool)
14779{
Daniel Veillard45490ae2008-07-29 09:13:19 +000014780 xmlXPathParserContextPtr pctxt;
Daniel Veillard81463942001-10-16 12:34:39 +000014781#ifndef LIBXML_THREAD_ENABLED
14782 static int reentance = 0;
14783#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014784 int res;
Owen Taylor3473f882001-02-23 17:55:21 +000014785
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014786 CHECK_CTXT_NEG(ctxt)
William M. Brackf13f77f2004-11-12 16:03:48 +000014787
14788 if (comp == NULL)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014789 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +000014790 xmlXPathInit();
14791
Daniel Veillard81463942001-10-16 12:34:39 +000014792#ifndef LIBXML_THREAD_ENABLED
14793 reentance++;
14794 if (reentance > 1)
14795 xmlXPathDisableOptimizer = 1;
14796#endif
14797
Daniel Veillardf06307e2001-07-03 10:35:50 +000014798#ifdef DEBUG_EVAL_COUNTS
14799 comp->nb++;
14800 if ((comp->string != NULL) && (comp->nb > 100)) {
14801 fprintf(stderr, "100 x %s\n", comp->string);
14802 comp->nb = 0;
14803 }
14804#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014805 pctxt = xmlXPathCompParserContext(comp, ctxt);
14806 res = xmlXPathRunEval(pctxt, toBool);
Owen Taylor3473f882001-02-23 17:55:21 +000014807
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014808 if (resObj) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014809 if (pctxt->value == NULL) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014810 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014811 "xmlXPathCompiledEval: evaluation failed\n");
Daniel Veillard45490ae2008-07-29 09:13:19 +000014812 *resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014813 } else {
14814 *resObj = valuePop(pctxt);
14815 }
Owen Taylor3473f882001-02-23 17:55:21 +000014816 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014817
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014818 /*
14819 * Pop all remaining objects from the stack.
14820 */
14821 if (pctxt->valueNr > 0) {
14822 xmlXPathObjectPtr tmp;
14823 int stack = 0;
14824
14825 do {
14826 tmp = valuePop(pctxt);
14827 if (tmp != NULL) {
Daniel Veillard45490ae2008-07-29 09:13:19 +000014828 stack++;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014829 xmlXPathReleaseObject(ctxt, tmp);
14830 }
14831 } while (tmp != NULL);
14832 if ((stack != 0) &&
14833 ((toBool) || ((resObj) && (*resObj))))
14834 {
14835 xmlGenericError(xmlGenericErrorContext,
14836 "xmlXPathCompiledEval: %d objects left on the stack.\n",
14837 stack);
14838 }
Owen Taylor3473f882001-02-23 17:55:21 +000014839 }
Daniel Veillard45490ae2008-07-29 09:13:19 +000014840
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014841 if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14842 xmlXPathFreeObject(*resObj);
14843 *resObj = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014844 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014845 pctxt->comp = NULL;
14846 xmlXPathFreeParserContext(pctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000014847#ifndef LIBXML_THREAD_ENABLED
14848 reentance--;
14849#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014850
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014851 return(res);
14852}
14853
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014854/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014855 * xmlXPathCompiledEval:
14856 * @comp: the compiled XPath expression
14857 * @ctx: the XPath context
14858 *
14859 * Evaluate the Precompiled XPath expression in the given context.
14860 *
14861 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14862 * the caller has to free the object.
14863 */
14864xmlXPathObjectPtr
14865xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14866{
14867 xmlXPathObjectPtr res = NULL;
14868
14869 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14870 return(res);
14871}
14872
14873/**
14874 * xmlXPathCompiledEvalToBoolean:
14875 * @comp: the compiled XPath expression
14876 * @ctxt: the XPath context
14877 *
14878 * Applies the XPath boolean() function on the result of the given
14879 * compiled expression.
14880 *
14881 * Returns 1 if the expression evaluated to true, 0 if to false and
14882 * -1 in API and internal errors.
14883 */
14884int
14885xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14886 xmlXPathContextPtr ctxt)
14887{
14888 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14889}
14890
14891/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014892 * xmlXPathEvalExpr:
14893 * @ctxt: the XPath Parser context
14894 *
14895 * Parse and evaluate an XPath expression in the given context,
14896 * then push the result on the context stack
14897 */
14898void
14899xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014900#ifdef XPATH_STREAMING
14901 xmlXPathCompExprPtr comp;
14902#endif
14903
Daniel Veillarda82b1822004-11-08 16:24:57 +000014904 if (ctxt == NULL) return;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014905
Daniel Veillard56de87e2005-02-16 00:22:29 +000014906#ifdef XPATH_STREAMING
14907 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14908 if (comp != NULL) {
14909 if (ctxt->comp != NULL)
14910 xmlXPathFreeCompExpr(ctxt->comp);
14911 ctxt->comp = comp;
14912 if (ctxt->cur != NULL)
14913 while (*ctxt->cur != 0) ctxt->cur++;
14914 } else
14915#endif
14916 {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014917 xmlXPathCompileExpr(ctxt, 1);
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014918 /*
14919 * In this scenario the expression string will sit in ctxt->base.
14920 */
14921 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
14922 (ctxt->comp != NULL) &&
14923 (ctxt->base != NULL) &&
Kasimier T. Buchcik7cb3fa92006-06-06 15:27:46 +000014924 (ctxt->comp->nbStep > 2) &&
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014925 (ctxt->comp->last >= 0) &&
14926 (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014927 {
14928 xmlXPathRewriteDOSExpression(ctxt->comp,
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014929 &ctxt->comp->steps[ctxt->comp->last]);
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014930 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014931 }
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000014932 CHECK_ERROR;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014933 xmlXPathRunEval(ctxt, 0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014934}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014935
14936/**
14937 * xmlXPathEval:
14938 * @str: the XPath expression
14939 * @ctx: the XPath context
14940 *
14941 * Evaluate the XPath Location Path in the given context.
14942 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014943 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014944 * the caller has to free the object.
14945 */
14946xmlXPathObjectPtr
14947xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14948 xmlXPathParserContextPtr ctxt;
14949 xmlXPathObjectPtr res, tmp, init = NULL;
14950 int stack = 0;
14951
William M. Brackf13f77f2004-11-12 16:03:48 +000014952 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014953
William M. Brackf13f77f2004-11-12 16:03:48 +000014954 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014955
14956 ctxt = xmlXPathNewParserContext(str, ctx);
William M. Brack11be2d02007-01-24 19:17:19 +000014957 if (ctxt == NULL)
14958 return NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014959 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014960
14961 if (ctxt->value == NULL) {
14962 xmlGenericError(xmlGenericErrorContext,
14963 "xmlXPathEval: evaluation failed\n");
14964 res = NULL;
Daniel Veillard45490ae2008-07-29 09:13:19 +000014965 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
Daniel Veillard56de87e2005-02-16 00:22:29 +000014966#ifdef XPATH_STREAMING
14967 && (ctxt->comp->stream == NULL)
14968#endif
14969 ) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014970 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14971 res = NULL;
14972 } else {
14973 res = valuePop(ctxt);
14974 }
14975
14976 do {
14977 tmp = valuePop(ctxt);
14978 if (tmp != NULL) {
14979 if (tmp != init)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014980 stack++;
14981 xmlXPathReleaseObject(ctx, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014982 }
14983 } while (tmp != NULL);
14984 if ((stack != 0) && (res != NULL)) {
14985 xmlGenericError(xmlGenericErrorContext,
14986 "xmlXPathEval: %d object left on the stack\n",
14987 stack);
14988 }
14989 if (ctxt->error != XPATH_EXPRESSION_OK) {
14990 xmlXPathFreeObject(res);
14991 res = NULL;
14992 }
14993
Owen Taylor3473f882001-02-23 17:55:21 +000014994 xmlXPathFreeParserContext(ctxt);
14995 return(res);
14996}
14997
14998/**
14999 * xmlXPathEvalExpression:
15000 * @str: the XPath expression
15001 * @ctxt: the XPath context
15002 *
15003 * Evaluate the XPath expression in the given context.
15004 *
15005 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15006 * the caller has to free the object.
15007 */
15008xmlXPathObjectPtr
15009xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
15010 xmlXPathParserContextPtr pctxt;
15011 xmlXPathObjectPtr res, tmp;
15012 int stack = 0;
15013
William M. Brackf13f77f2004-11-12 16:03:48 +000015014 CHECK_CTXT(ctxt)
Owen Taylor3473f882001-02-23 17:55:21 +000015015
William M. Brackf13f77f2004-11-12 16:03:48 +000015016 xmlXPathInit();
Owen Taylor3473f882001-02-23 17:55:21 +000015017
15018 pctxt = xmlXPathNewParserContext(str, ctxt);
William M. Brack11be2d02007-01-24 19:17:19 +000015019 if (pctxt == NULL)
15020 return NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000015021 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000015022
Daniel Veillardc465ffc2006-10-17 19:39:33 +000015023 if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
Owen Taylor3473f882001-02-23 17:55:21 +000015024 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
15025 res = NULL;
15026 } else {
15027 res = valuePop(pctxt);
15028 }
15029 do {
15030 tmp = valuePop(pctxt);
15031 if (tmp != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015032 xmlXPathReleaseObject(ctxt, tmp);
Owen Taylor3473f882001-02-23 17:55:21 +000015033 stack++;
15034 }
15035 } while (tmp != NULL);
15036 if ((stack != 0) && (res != NULL)) {
15037 xmlGenericError(xmlGenericErrorContext,
15038 "xmlXPathEvalExpression: %d object left on the stack\n",
15039 stack);
15040 }
15041 xmlXPathFreeParserContext(pctxt);
15042 return(res);
15043}
15044
Daniel Veillard42766c02002-08-22 20:52:17 +000015045/************************************************************************
15046 * *
15047 * Extra functions not pertaining to the XPath spec *
15048 * *
15049 ************************************************************************/
15050/**
15051 * xmlXPathEscapeUriFunction:
15052 * @ctxt: the XPath Parser context
15053 * @nargs: the number of arguments
15054 *
15055 * Implement the escape-uri() XPath function
15056 * string escape-uri(string $str, bool $escape-reserved)
15057 *
15058 * This function applies the URI escaping rules defined in section 2 of [RFC
15059 * 2396] to the string supplied as $uri-part, which typically represents all
15060 * or part of a URI. The effect of the function is to replace any special
15061 * character in the string by an escape sequence of the form %xx%yy...,
15062 * where xxyy... is the hexadecimal representation of the octets used to
15063 * represent the character in UTF-8.
15064 *
15065 * The set of characters that are escaped depends on the setting of the
15066 * boolean argument $escape-reserved.
15067 *
15068 * If $escape-reserved is true, all characters are escaped other than lower
15069 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15070 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15071 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15072 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15073 * A-F).
15074 *
15075 * If $escape-reserved is false, the behavior differs in that characters
15076 * referred to in [RFC 2396] as reserved characters are not escaped. These
15077 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
Daniel Veillard45490ae2008-07-29 09:13:19 +000015078 *
Daniel Veillard42766c02002-08-22 20:52:17 +000015079 * [RFC 2396] does not define whether escaped URIs should use lower case or
15080 * upper case for hexadecimal digits. To ensure that escaped URIs can be
15081 * compared using string comparison functions, this function must always use
15082 * the upper-case letters A-F.
Daniel Veillard45490ae2008-07-29 09:13:19 +000015083 *
Daniel Veillard42766c02002-08-22 20:52:17 +000015084 * Generally, $escape-reserved should be set to true when escaping a string
15085 * that is to form a single part of a URI, and to false when escaping an
15086 * entire URI or URI reference.
Daniel Veillard45490ae2008-07-29 09:13:19 +000015087 *
15088 * In the case of non-ascii characters, the string is encoded according to
Daniel Veillard42766c02002-08-22 20:52:17 +000015089 * utf-8 and then converted according to RFC 2396.
15090 *
15091 * Examples
Daniel Veillard45490ae2008-07-29 09:13:19 +000015092 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
Daniel Veillard42766c02002-08-22 20:52:17 +000015093 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15094 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15095 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15096 *
15097 */
Daniel Veillard118aed72002-09-24 14:13:13 +000015098static void
Daniel Veillard42766c02002-08-22 20:52:17 +000015099xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15100 xmlXPathObjectPtr str;
15101 int escape_reserved;
Daniel Veillardade10f22012-07-12 09:43:27 +080015102 xmlBufPtr target;
Daniel Veillard42766c02002-08-22 20:52:17 +000015103 xmlChar *cptr;
15104 xmlChar escape[4];
Daniel Veillard45490ae2008-07-29 09:13:19 +000015105
Daniel Veillard42766c02002-08-22 20:52:17 +000015106 CHECK_ARITY(2);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015107
Daniel Veillard42766c02002-08-22 20:52:17 +000015108 escape_reserved = xmlXPathPopBoolean(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015109
Daniel Veillard42766c02002-08-22 20:52:17 +000015110 CAST_TO_STRING;
15111 str = valuePop(ctxt);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015112
Daniel Veillardade10f22012-07-12 09:43:27 +080015113 target = xmlBufCreate();
Daniel Veillard45490ae2008-07-29 09:13:19 +000015114
Daniel Veillard42766c02002-08-22 20:52:17 +000015115 escape[0] = '%';
15116 escape[3] = 0;
Daniel Veillard45490ae2008-07-29 09:13:19 +000015117
Daniel Veillard42766c02002-08-22 20:52:17 +000015118 if (target) {
15119 for (cptr = str->stringval; *cptr; cptr++) {
15120 if ((*cptr >= 'A' && *cptr <= 'Z') ||
15121 (*cptr >= 'a' && *cptr <= 'z') ||
15122 (*cptr >= '0' && *cptr <= '9') ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000015123 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
Daniel Veillard42766c02002-08-22 20:52:17 +000015124 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
15125 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
Daniel Veillard45490ae2008-07-29 09:13:19 +000015126 (*cptr == '%' &&
Daniel Veillard42766c02002-08-22 20:52:17 +000015127 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15128 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15129 (cptr[1] >= '0' && cptr[1] <= '9')) &&
15130 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15131 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15132 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15133 (!escape_reserved &&
15134 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15135 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15136 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15137 *cptr == ','))) {
Daniel Veillardade10f22012-07-12 09:43:27 +080015138 xmlBufAdd(target, cptr, 1);
Daniel Veillard42766c02002-08-22 20:52:17 +000015139 } else {
15140 if ((*cptr >> 4) < 10)
15141 escape[1] = '0' + (*cptr >> 4);
15142 else
15143 escape[1] = 'A' - 10 + (*cptr >> 4);
15144 if ((*cptr & 0xF) < 10)
15145 escape[2] = '0' + (*cptr & 0xF);
15146 else
15147 escape[2] = 'A' - 10 + (*cptr & 0xF);
Daniel Veillard45490ae2008-07-29 09:13:19 +000015148
Daniel Veillardade10f22012-07-12 09:43:27 +080015149 xmlBufAdd(target, &escape[0], 3);
Daniel Veillard42766c02002-08-22 20:52:17 +000015150 }
15151 }
15152 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015153 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Daniel Veillardade10f22012-07-12 09:43:27 +080015154 xmlBufContent(target)));
15155 xmlBufFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015156 xmlXPathReleaseObject(ctxt->context, str);
Daniel Veillard42766c02002-08-22 20:52:17 +000015157}
15158
Owen Taylor3473f882001-02-23 17:55:21 +000015159/**
15160 * xmlXPathRegisterAllFunctions:
15161 * @ctxt: the XPath context
15162 *
15163 * Registers all default XPath functions in this context
15164 */
15165void
15166xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15167{
15168 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15169 xmlXPathBooleanFunction);
15170 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15171 xmlXPathCeilingFunction);
15172 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15173 xmlXPathCountFunction);
15174 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15175 xmlXPathConcatFunction);
15176 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15177 xmlXPathContainsFunction);
15178 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15179 xmlXPathIdFunction);
15180 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15181 xmlXPathFalseFunction);
15182 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15183 xmlXPathFloorFunction);
15184 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15185 xmlXPathLastFunction);
15186 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15187 xmlXPathLangFunction);
15188 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15189 xmlXPathLocalNameFunction);
15190 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15191 xmlXPathNotFunction);
15192 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15193 xmlXPathNameFunction);
15194 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15195 xmlXPathNamespaceURIFunction);
15196 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15197 xmlXPathNormalizeFunction);
15198 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15199 xmlXPathNumberFunction);
15200 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15201 xmlXPathPositionFunction);
15202 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15203 xmlXPathRoundFunction);
15204 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15205 xmlXPathStringFunction);
15206 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15207 xmlXPathStringLengthFunction);
15208 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15209 xmlXPathStartsWithFunction);
15210 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15211 xmlXPathSubstringFunction);
15212 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15213 xmlXPathSubstringBeforeFunction);
15214 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15215 xmlXPathSubstringAfterFunction);
15216 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15217 xmlXPathSumFunction);
15218 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15219 xmlXPathTrueFunction);
15220 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15221 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000015222
15223 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15224 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15225 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000015226}
15227
15228#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000015229#define bottom_xpath
15230#include "elfgcchack.h"