blob: 06d670d94e92fccfca688eb1e5fcbf369dd86277 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005 *f
Owen Taylor3473f882001-02-23 17:55:21 +00006 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011 * See Copyright for the status of this software
Owen Taylor3473f882001-02-23 17:55:21 +000012 *
Daniel Veillardc5d64342001-06-24 12:13:24 +000013 * Author: daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000014 *
Owen Taylor3473f882001-02-23 17:55:21 +000015 */
16
Daniel Veillard34ce8be2002-03-18 19:37:11 +000017#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000018#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000019
Owen Taylor3473f882001-02-23 17:55:21 +000020#include <string.h>
21
22#ifdef HAVE_SYS_TYPES_H
23#include <sys/types.h>
24#endif
25#ifdef HAVE_MATH_H
26#include <math.h>
27#endif
28#ifdef HAVE_FLOAT_H
29#include <float.h>
30#endif
Owen Taylor3473f882001-02-23 17:55:21 +000031#ifdef HAVE_CTYPE_H
32#include <ctype.h>
33#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000034#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000035#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000036#endif
Owen Taylor3473f882001-02-23 17:55:21 +000037
38#include <libxml/xmlmemory.h>
39#include <libxml/tree.h>
40#include <libxml/valid.h>
41#include <libxml/xpath.h>
42#include <libxml/xpathInternals.h>
43#include <libxml/parserInternals.h>
44#include <libxml/hash.h>
45#ifdef LIBXML_XPTR_ENABLED
46#include <libxml/xpointer.h>
47#endif
48#ifdef LIBXML_DEBUG_ENABLED
49#include <libxml/debugXML.h>
50#endif
51#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000052#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000053#include <libxml/globals.h>
Daniel Veillard56de87e2005-02-16 00:22:29 +000054#ifdef LIBXML_PATTERN_ENABLED
55#include <libxml/pattern.h>
56#endif
57
58#ifdef LIBXML_PATTERN_ENABLED
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000059#define XPATH_STREAMING
Daniel Veillard56de87e2005-02-16 00:22:29 +000060#endif
Owen Taylor3473f882001-02-23 17:55:21 +000061
Daniel Veillardd96f6d32003-10-07 21:25:12 +000062#define TODO \
63 xmlGenericError(xmlGenericErrorContext, \
64 "Unimplemented block at %s:%d\n", \
65 __FILE__, __LINE__);
66
William M. Brackd1757ab2004-10-02 22:07:48 +000067/*
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000068* XP_OPTIMIZED_NON_ELEM_COMPARISON:
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +000069* If defined, this will use xmlXPathCmpNodesExt() instead of
70* xmlXPathCmpNodes(). The new function is optimized comparison of
71* non-element nodes; actually it will speed up comparison only if
72* xmlXPathOrderDocElems() was called in order to index the elements of
73* a tree in document order; Libxslt does such an indexing, thus it will
74* benefit from this optimization.
75*/
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000076#define XP_OPTIMIZED_NON_ELEM_COMPARISON
77
78/*
79* XP_OPTIMIZED_FILTER_FIRST:
80* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
81* in a way, that it stop evaluation at the first node.
82*/
83#define XP_OPTIMIZED_FILTER_FIRST
84
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000085/*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000086* XP_DEBUG_OBJ_USAGE:
87* Internal flag to enable tracking of how much XPath objects have been
88* created.
89*/
90/* #define XP_DEBUG_OBJ_USAGE */
91
92/*
William M. Brackd1757ab2004-10-02 22:07:48 +000093 * TODO:
94 * There are a few spots where some tests are done which depend upon ascii
95 * data. These should be enhanced for full UTF8 support (see particularly
96 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
97 */
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000098
William M. Brack21e4ef22005-01-02 09:53:13 +000099#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000100
101/************************************************************************
102 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000103 * Floating point stuff *
104 * *
105 ************************************************************************/
106
Daniel Veillardc0631a62001-09-20 13:56:06 +0000107#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +0000108#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +0000109#endif
Daniel Veillardcda96922001-08-21 10:56:31 +0000110#include "trionan.c"
111
Owen Taylor3473f882001-02-23 17:55:21 +0000112/*
Owen Taylor3473f882001-02-23 17:55:21 +0000113 * The lack of portability of this section of the libc is annoying !
114 */
115double xmlXPathNAN = 0;
116double xmlXPathPINF = 1;
117double xmlXPathNINF = -1;
Daniel Veillard24505b02005-07-28 23:49:35 +0000118static double xmlXPathNZERO = 0; /* not exported from headers */
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000119static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000120
Owen Taylor3473f882001-02-23 17:55:21 +0000121/**
122 * xmlXPathInit:
123 *
124 * Initialize the XPath environment
125 */
126void
127xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000128 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +0000129
Bjorn Reese45029602001-08-21 09:23:53 +0000130 xmlXPathPINF = trio_pinf();
131 xmlXPathNINF = trio_ninf();
132 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000133 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +0000134
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000135 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000136}
137
Daniel Veillardcda96922001-08-21 10:56:31 +0000138/**
139 * xmlXPathIsNaN:
140 * @val: a double value
141 *
142 * Provides a portable isnan() function to detect whether a double
143 * is a NotaNumber. Based on trio code
144 * http://sourceforge.net/projects/ctrio/
145 *
146 * Returns 1 if the value is a NaN, 0 otherwise
147 */
148int
149xmlXPathIsNaN(double val) {
150 return(trio_isnan(val));
151}
152
153/**
154 * xmlXPathIsInf:
155 * @val: a double value
156 *
157 * Provides a portable isinf() function to detect whether a double
158 * is a +Infinite or -Infinite. Based on trio code
159 * http://sourceforge.net/projects/ctrio/
160 *
161 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
162 */
163int
164xmlXPathIsInf(double val) {
165 return(trio_isinf(val));
166}
167
Daniel Veillard4432df22003-09-28 18:58:27 +0000168#endif /* SCHEMAS or XPATH */
169#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000170/**
171 * xmlXPathGetSign:
172 * @val: a double value
173 *
174 * Provides a portable function to detect the sign of a double
175 * Modified from trio code
176 * http://sourceforge.net/projects/ctrio/
177 *
178 * Returns 1 if the value is Negative, 0 if positive
179 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000180static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000181xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000182 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000183}
184
185
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000186/*
187 * TODO: when compatibility allows remove all "fake node libxslt" strings
188 * the test should just be name[0] = ' '
189 */
190/* #define DEBUG */
191/* #define DEBUG_STEP */
192/* #define DEBUG_STEP_NTH */
193/* #define DEBUG_EXPR */
194/* #define DEBUG_EVAL_COUNTS */
195
196static xmlNs xmlXPathXMLNamespaceStruct = {
197 NULL,
198 XML_NAMESPACE_DECL,
199 XML_XML_NAMESPACE,
200 BAD_CAST "xml",
201 NULL
202};
203static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
204#ifndef LIBXML_THREAD_ENABLED
205/*
206 * Optimizer is disabled only when threaded apps are detected while
207 * the library ain't compiled for thread safety.
208 */
209static int xmlXPathDisableOptimizer = 0;
210#endif
211
Owen Taylor3473f882001-02-23 17:55:21 +0000212/************************************************************************
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000213 * *
214 * Error handling routines *
215 * *
216 ************************************************************************/
217
Daniel Veillard24505b02005-07-28 23:49:35 +0000218/**
219 * XP_ERRORNULL:
220 * @X: the error code
221 *
222 * Macro to raise an XPath error and return NULL.
223 */
224#define XP_ERRORNULL(X) \
225 { xmlXPathErr(ctxt, X); return(NULL); }
226
William M. Brack08171912003-12-29 02:52:11 +0000227/*
228 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
229 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000230static const char *xmlXPathErrorMessages[] = {
231 "Ok\n",
232 "Number encoding\n",
233 "Unfinished literal\n",
234 "Start of literal\n",
235 "Expected $ for variable reference\n",
236 "Undefined variable\n",
237 "Invalid predicate\n",
238 "Invalid expression\n",
239 "Missing closing curly brace\n",
240 "Unregistered function\n",
241 "Invalid operand\n",
242 "Invalid type\n",
243 "Invalid number of arguments\n",
244 "Invalid context size\n",
245 "Invalid context position\n",
246 "Memory allocation error\n",
247 "Syntax error\n",
248 "Resource error\n",
249 "Sub resource error\n",
250 "Undefined namespace prefix\n",
251 "Encoding error\n",
Daniel Veillard57b25162004-11-06 14:50:18 +0000252 "Char out of XML range\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000253 "Invalid or incomplete context\n",
254 "?? Unknown error ??\n" /* Must be last in the list! */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000255};
William M. Brackcd65bc92005-01-06 09:39:18 +0000256#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
257 sizeof(xmlXPathErrorMessages[0])) - 1)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000258/**
259 * xmlXPathErrMemory:
260 * @ctxt: an XPath context
261 * @extra: extra informations
262 *
263 * Handle a redefinition of attribute error
264 */
265static void
266xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
267{
268 if (ctxt != NULL) {
269 if (extra) {
270 xmlChar buf[200];
271
272 xmlStrPrintf(buf, 200,
273 BAD_CAST "Memory allocation failed : %s\n",
274 extra);
275 ctxt->lastError.message = (char *) xmlStrdup(buf);
276 } else {
277 ctxt->lastError.message = (char *)
278 xmlStrdup(BAD_CAST "Memory allocation failed\n");
279 }
280 ctxt->lastError.domain = XML_FROM_XPATH;
281 ctxt->lastError.code = XML_ERR_NO_MEMORY;
282 if (ctxt->error != NULL)
283 ctxt->error(ctxt->userData, &ctxt->lastError);
284 } else {
285 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000286 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000287 NULL, NULL, XML_FROM_XPATH,
288 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
289 extra, NULL, NULL, 0, 0,
290 "Memory allocation failed : %s\n", extra);
291 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000292 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000293 NULL, NULL, XML_FROM_XPATH,
294 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
295 NULL, NULL, NULL, 0, 0,
296 "Memory allocation failed\n");
297 }
298}
299
300/**
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000301 * xmlXPathPErrMemory:
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000302 * @ctxt: an XPath parser context
303 * @extra: extra informations
304 *
305 * Handle a redefinition of attribute error
306 */
307static void
308xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
309{
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000310 if (ctxt == NULL)
311 xmlXPathErrMemory(NULL, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000312 else {
313 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000314 xmlXPathErrMemory(ctxt->context, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000315 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000316}
317
318/**
319 * xmlXPathErr:
320 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000321 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000322 *
William M. Brackcd65bc92005-01-06 09:39:18 +0000323 * Handle an XPath error
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000324 */
325void
326xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
327{
William M. Brackcd65bc92005-01-06 09:39:18 +0000328 if ((error < 0) || (error > MAXERRNO))
329 error = MAXERRNO;
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000330 if (ctxt == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000331 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000332 NULL, NULL, XML_FROM_XPATH,
333 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
334 XML_ERR_ERROR, NULL, 0,
335 NULL, NULL, NULL, 0, 0,
336 xmlXPathErrorMessages[error]);
337 return;
338 }
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000339 ctxt->error = error;
340 if (ctxt->context == NULL) {
341 __xmlRaiseError(NULL, NULL, NULL,
342 NULL, NULL, XML_FROM_XPATH,
343 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
344 XML_ERR_ERROR, NULL, 0,
345 (const char *) ctxt->base, NULL, NULL,
346 ctxt->cur - ctxt->base, 0,
347 xmlXPathErrorMessages[error]);
348 return;
349 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +0000350
351 /* cleanup current last error */
352 xmlResetError(&ctxt->context->lastError);
353
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000354 ctxt->context->lastError.domain = XML_FROM_XPATH;
355 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
356 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000357 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000358 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
359 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
360 ctxt->context->lastError.node = ctxt->context->debugNode;
361 if (ctxt->context->error != NULL) {
362 ctxt->context->error(ctxt->context->userData,
363 &ctxt->context->lastError);
364 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000365 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000366 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
367 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
368 XML_ERR_ERROR, NULL, 0,
369 (const char *) ctxt->base, NULL, NULL,
370 ctxt->cur - ctxt->base, 0,
371 xmlXPathErrorMessages[error]);
372 }
373
374}
375
376/**
377 * xmlXPatherror:
378 * @ctxt: the XPath Parser context
379 * @file: the file name
380 * @line: the line number
381 * @no: the error number
382 *
383 * Formats an error message.
384 */
385void
386xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
387 int line ATTRIBUTE_UNUSED, int no) {
388 xmlXPathErr(ctxt, no);
389}
390
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000391/************************************************************************
392 * *
393 * Utilities *
394 * *
395 ************************************************************************/
396
397/**
398 * xsltPointerList:
399 *
400 * Pointer-list for various purposes.
401 */
402typedef struct _xmlPointerList xmlPointerList;
403typedef xmlPointerList *xmlPointerListPtr;
404struct _xmlPointerList {
405 void **items;
406 int number;
407 int size;
408};
409/*
410* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
411* and here, we should make the functions public.
412*/
413static int
414xmlPointerListAddSize(xmlPointerListPtr list,
415 void *item,
416 int initialSize)
417{
418 if (list->items == NULL) {
419 if (initialSize <= 0)
420 initialSize = 1;
421 list->items = (void **) xmlMalloc(
422 initialSize * sizeof(void *));
423 if (list->items == NULL) {
424 xmlXPathErrMemory(NULL,
425 "xmlPointerListCreate: allocating item\n");
426 return(-1);
427 }
428 list->number = 0;
429 list->size = initialSize;
430 } else if (list->size <= list->number) {
431 list->size *= 2;
432 list->items = (void **) xmlRealloc(list->items,
433 list->size * sizeof(void *));
434 if (list->items == NULL) {
435 xmlXPathErrMemory(NULL,
436 "xmlPointerListCreate: re-allocating item\n");
437 list->size = 0;
438 return(-1);
439 }
440 }
441 list->items[list->number++] = item;
442 return(0);
443}
444
445/**
446 * xsltPointerListCreate:
447 *
448 * Creates an xsltPointerList structure.
449 *
450 * Returns a xsltPointerList structure or NULL in case of an error.
451 */
452static xmlPointerListPtr
453xmlPointerListCreate(int initialSize)
454{
455 xmlPointerListPtr ret;
456
457 ret = xmlMalloc(sizeof(xmlPointerList));
458 if (ret == NULL) {
459 xmlXPathErrMemory(NULL,
460 "xmlPointerListCreate: allocating item\n");
461 return (NULL);
462 }
463 memset(ret, 0, sizeof(xmlPointerList));
464 if (initialSize > 0) {
465 xmlPointerListAddSize(ret, NULL, initialSize);
466 ret->number = 0;
467 }
468 return (ret);
469}
470
471/**
472 * xsltPointerListFree:
473 *
474 * Frees the xsltPointerList structure. This does not free
475 * the content of the list.
476 */
477static void
478xmlPointerListFree(xmlPointerListPtr list)
479{
480 if (list == NULL)
481 return;
482 if (list->items != NULL)
483 xmlFree(list->items);
484 xmlFree(list);
485}
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000486
487/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000488 * *
489 * Parser Types *
490 * *
491 ************************************************************************/
492
493/*
494 * Types are private:
495 */
496
497typedef enum {
498 XPATH_OP_END=0,
499 XPATH_OP_AND,
500 XPATH_OP_OR,
501 XPATH_OP_EQUAL,
502 XPATH_OP_CMP,
503 XPATH_OP_PLUS,
504 XPATH_OP_MULT,
505 XPATH_OP_UNION,
506 XPATH_OP_ROOT,
507 XPATH_OP_NODE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000508 XPATH_OP_RESET, /* 10 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000509 XPATH_OP_COLLECT,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000510 XPATH_OP_VALUE, /* 12 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000511 XPATH_OP_VARIABLE,
512 XPATH_OP_FUNCTION,
513 XPATH_OP_ARG,
514 XPATH_OP_PREDICATE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000515 XPATH_OP_FILTER, /* 17 */
516 XPATH_OP_SORT /* 18 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000517#ifdef LIBXML_XPTR_ENABLED
518 ,XPATH_OP_RANGETO
519#endif
520} xmlXPathOp;
521
522typedef enum {
523 AXIS_ANCESTOR = 1,
524 AXIS_ANCESTOR_OR_SELF,
525 AXIS_ATTRIBUTE,
526 AXIS_CHILD,
527 AXIS_DESCENDANT,
528 AXIS_DESCENDANT_OR_SELF,
529 AXIS_FOLLOWING,
530 AXIS_FOLLOWING_SIBLING,
531 AXIS_NAMESPACE,
532 AXIS_PARENT,
533 AXIS_PRECEDING,
534 AXIS_PRECEDING_SIBLING,
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +0000535 AXIS_SELF
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000536} xmlXPathAxisVal;
537
538typedef enum {
539 NODE_TEST_NONE = 0,
540 NODE_TEST_TYPE = 1,
541 NODE_TEST_PI = 2,
542 NODE_TEST_ALL = 3,
543 NODE_TEST_NS = 4,
544 NODE_TEST_NAME = 5
545} xmlXPathTestVal;
546
547typedef enum {
548 NODE_TYPE_NODE = 0,
549 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
550 NODE_TYPE_TEXT = XML_TEXT_NODE,
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +0000551 NODE_TYPE_PI = XML_PI_NODE
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000552} xmlXPathTypeVal;
553
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +0000554#define XP_REWRITE_DOS_CHILD_ELEM 1
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000555
556typedef struct _xmlXPathStepOp xmlXPathStepOp;
557typedef xmlXPathStepOp *xmlXPathStepOpPtr;
558struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000559 xmlXPathOp op; /* The identifier of the operation */
560 int ch1; /* First child */
561 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000562 int value;
563 int value2;
564 int value3;
565 void *value4;
566 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000567 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000568 void *cacheURI;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +0000569 int rewriteType;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000570};
571
572struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000573 int nbStep; /* Number of steps in this expression */
574 int maxStep; /* Maximum number of steps allocated */
575 xmlXPathStepOp *steps; /* ops for computation of this expression */
576 int last; /* index of last step in expression */
577 xmlChar *expr; /* the expression being computed */
Daniel Veillard4773df22004-01-23 13:15:13 +0000578 xmlDictPtr dict; /* the dictionnary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000579#ifdef DEBUG_EVAL_COUNTS
580 int nb;
581 xmlChar *string;
582#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000583#ifdef XPATH_STREAMING
584 xmlPatternPtr stream;
585#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000586};
587
588/************************************************************************
589 * *
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000590 * Forward declarations *
591 * *
592 ************************************************************************/
593static void
594xmlXPathFreeValueTree(xmlNodeSetPtr obj);
595static void
596xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
597static int
598xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
599 xmlXPathStepOpPtr op, xmlNodePtr *first);
600static int
601xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +0000602 xmlXPathStepOpPtr op,
603 int isPredicate);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000604
605/************************************************************************
606 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000607 * Parser Type functions *
608 * *
609 ************************************************************************/
610
611/**
612 * xmlXPathNewCompExpr:
613 *
614 * Create a new Xpath component
615 *
616 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
617 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000618static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000619xmlXPathNewCompExpr(void) {
620 xmlXPathCompExprPtr cur;
621
622 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
623 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000624 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000625 return(NULL);
626 }
627 memset(cur, 0, sizeof(xmlXPathCompExpr));
628 cur->maxStep = 10;
629 cur->nbStep = 0;
630 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
631 sizeof(xmlXPathStepOp));
632 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000633 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000634 xmlFree(cur);
635 return(NULL);
636 }
637 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
638 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000639#ifdef DEBUG_EVAL_COUNTS
640 cur->nb = 0;
641#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000642 return(cur);
643}
644
645/**
646 * xmlXPathFreeCompExpr:
647 * @comp: an XPATH comp
648 *
649 * Free up the memory allocated by @comp
650 */
651void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000652xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
653{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000654 xmlXPathStepOpPtr op;
655 int i;
656
657 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000658 return;
Daniel Veillard4773df22004-01-23 13:15:13 +0000659 if (comp->dict == NULL) {
660 for (i = 0; i < comp->nbStep; i++) {
661 op = &comp->steps[i];
662 if (op->value4 != NULL) {
663 if (op->op == XPATH_OP_VALUE)
664 xmlXPathFreeObject(op->value4);
665 else
666 xmlFree(op->value4);
667 }
668 if (op->value5 != NULL)
669 xmlFree(op->value5);
670 }
671 } else {
672 for (i = 0; i < comp->nbStep; i++) {
673 op = &comp->steps[i];
674 if (op->value4 != NULL) {
675 if (op->op == XPATH_OP_VALUE)
676 xmlXPathFreeObject(op->value4);
677 }
678 }
679 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000680 }
681 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000682 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000683 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000684#ifdef DEBUG_EVAL_COUNTS
685 if (comp->string != NULL) {
686 xmlFree(comp->string);
687 }
688#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000689#ifdef XPATH_STREAMING
690 if (comp->stream != NULL) {
691 xmlFreePatternList(comp->stream);
692 }
693#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000694 if (comp->expr != NULL) {
695 xmlFree(comp->expr);
696 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000697
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000698 xmlFree(comp);
699}
700
701/**
702 * xmlXPathCompExprAdd:
703 * @comp: the compiled expression
704 * @ch1: first child index
705 * @ch2: second child index
706 * @op: an op
707 * @value: the first int value
708 * @value2: the second int value
709 * @value3: the third int value
710 * @value4: the first string value
711 * @value5: the second string value
712 *
William M. Brack08171912003-12-29 02:52:11 +0000713 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000714 *
715 * Returns -1 in case of failure, the index otherwise
716 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000717static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000718xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
719 xmlXPathOp op, int value,
720 int value2, int value3, void *value4, void *value5) {
721 if (comp->nbStep >= comp->maxStep) {
722 xmlXPathStepOp *real;
723
724 comp->maxStep *= 2;
725 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
726 comp->maxStep * sizeof(xmlXPathStepOp));
727 if (real == NULL) {
728 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000729 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000730 return(-1);
731 }
732 comp->steps = real;
733 }
734 comp->last = comp->nbStep;
Kasimier T. Buchcik6422d912006-06-26 14:31:53 +0000735 comp->steps[comp->nbStep].rewriteType = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000736 comp->steps[comp->nbStep].ch1 = ch1;
737 comp->steps[comp->nbStep].ch2 = ch2;
738 comp->steps[comp->nbStep].op = op;
739 comp->steps[comp->nbStep].value = value;
740 comp->steps[comp->nbStep].value2 = value2;
741 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +0000742 if ((comp->dict != NULL) &&
743 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
744 (op == XPATH_OP_COLLECT))) {
745 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000746 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000747 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000748 xmlFree(value4);
749 } else
750 comp->steps[comp->nbStep].value4 = NULL;
751 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000752 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000753 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000754 xmlFree(value5);
755 } else
756 comp->steps[comp->nbStep].value5 = NULL;
757 } else {
758 comp->steps[comp->nbStep].value4 = value4;
759 comp->steps[comp->nbStep].value5 = value5;
760 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000761 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000762 return(comp->nbStep++);
763}
764
Daniel Veillardf06307e2001-07-03 10:35:50 +0000765/**
766 * xmlXPathCompSwap:
767 * @comp: the compiled expression
768 * @op: operation index
769 *
770 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000771 */
772static void
773xmlXPathCompSwap(xmlXPathStepOpPtr op) {
774 int tmp;
775
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000776#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000777 /*
778 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +0000779 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +0000780 * application
781 */
782 if (xmlXPathDisableOptimizer)
783 return;
784#endif
785
Daniel Veillardf06307e2001-07-03 10:35:50 +0000786 tmp = op->ch1;
787 op->ch1 = op->ch2;
788 op->ch2 = tmp;
789}
790
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000791#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
792 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
793 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000794#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
795 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
796 (op), (val), (val2), (val3), (val4), (val5))
797
798#define PUSH_LEAVE_EXPR(op, val, val2) \
799xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
800
801#define PUSH_UNARY_EXPR(op, ch, val, val2) \
802xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
803
804#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +0000805xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
806 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000807
808/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000809 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000810 * XPath object cache structures *
811 * *
812 ************************************************************************/
813
814/* #define XP_DEFAULT_CACHE_ON */
815
Kasimier T. Buchcik58694692006-05-31 12:37:28 +0000816#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000817
Kasimier T. Buchcik58694692006-05-31 12:37:28 +0000818typedef struct _xmlXPathContextCache xmlXPathContextCache;
819typedef xmlXPathContextCache *xmlXPathContextCachePtr;
820struct _xmlXPathContextCache {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +0000821 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
822 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
823 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
824 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
825 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000826 int maxNodeset;
827 int maxString;
828 int maxBoolean;
829 int maxNumber;
830 int maxMisc;
831#ifdef XP_DEBUG_OBJ_USAGE
832 int dbgCachedAll;
833 int dbgCachedNodeset;
834 int dbgCachedString;
835 int dbgCachedBool;
836 int dbgCachedNumber;
837 int dbgCachedPoint;
838 int dbgCachedRange;
839 int dbgCachedLocset;
840 int dbgCachedUsers;
841 int dbgCachedXSLTTree;
842 int dbgCachedUndefined;
843
844
845 int dbgReusedAll;
846 int dbgReusedNodeset;
847 int dbgReusedString;
848 int dbgReusedBool;
849 int dbgReusedNumber;
850 int dbgReusedPoint;
851 int dbgReusedRange;
852 int dbgReusedLocset;
853 int dbgReusedUsers;
854 int dbgReusedXSLTTree;
855 int dbgReusedUndefined;
856
857#endif
858};
859
860/************************************************************************
861 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000862 * Debugging related functions *
863 * *
864 ************************************************************************/
865
Owen Taylor3473f882001-02-23 17:55:21 +0000866#define STRANGE \
867 xmlGenericError(xmlGenericErrorContext, \
868 "Internal error at %s:%d\n", \
869 __FILE__, __LINE__);
870
871#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000872static void
873xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000874 int i;
875 char shift[100];
876
877 for (i = 0;((i < depth) && (i < 25));i++)
878 shift[2 * i] = shift[2 * i + 1] = ' ';
879 shift[2 * i] = shift[2 * i + 1] = 0;
880 if (cur == NULL) {
881 fprintf(output, shift);
882 fprintf(output, "Node is NULL !\n");
883 return;
884
885 }
886
887 if ((cur->type == XML_DOCUMENT_NODE) ||
888 (cur->type == XML_HTML_DOCUMENT_NODE)) {
889 fprintf(output, shift);
890 fprintf(output, " /\n");
891 } else if (cur->type == XML_ATTRIBUTE_NODE)
892 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
893 else
894 xmlDebugDumpOneNode(output, cur, depth);
895}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000896static void
897xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000898 xmlNodePtr tmp;
899 int i;
900 char shift[100];
901
902 for (i = 0;((i < depth) && (i < 25));i++)
903 shift[2 * i] = shift[2 * i + 1] = ' ';
904 shift[2 * i] = shift[2 * i + 1] = 0;
905 if (cur == NULL) {
906 fprintf(output, shift);
907 fprintf(output, "Node is NULL !\n");
908 return;
909
910 }
911
912 while (cur != NULL) {
913 tmp = cur;
914 cur = cur->next;
915 xmlDebugDumpOneNode(output, tmp, depth);
916 }
917}
Owen Taylor3473f882001-02-23 17:55:21 +0000918
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000919static void
920xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000921 int i;
922 char shift[100];
923
924 for (i = 0;((i < depth) && (i < 25));i++)
925 shift[2 * i] = shift[2 * i + 1] = ' ';
926 shift[2 * i] = shift[2 * i + 1] = 0;
927
928 if (cur == NULL) {
929 fprintf(output, shift);
930 fprintf(output, "NodeSet is NULL !\n");
931 return;
932
933 }
934
Daniel Veillard911f49a2001-04-07 15:39:35 +0000935 if (cur != NULL) {
936 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
937 for (i = 0;i < cur->nodeNr;i++) {
938 fprintf(output, shift);
939 fprintf(output, "%d", i + 1);
940 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
941 }
Owen Taylor3473f882001-02-23 17:55:21 +0000942 }
943}
944
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000945static void
946xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000947 int i;
948 char shift[100];
949
950 for (i = 0;((i < depth) && (i < 25));i++)
951 shift[2 * i] = shift[2 * i + 1] = ' ';
952 shift[2 * i] = shift[2 * i + 1] = 0;
953
954 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
955 fprintf(output, shift);
956 fprintf(output, "Value Tree is NULL !\n");
957 return;
958
959 }
960
961 fprintf(output, shift);
962 fprintf(output, "%d", i + 1);
963 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
964}
Owen Taylor3473f882001-02-23 17:55:21 +0000965#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000966static void
967xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000968 int i;
969 char shift[100];
970
971 for (i = 0;((i < depth) && (i < 25));i++)
972 shift[2 * i] = shift[2 * i + 1] = ' ';
973 shift[2 * i] = shift[2 * i + 1] = 0;
974
975 if (cur == NULL) {
976 fprintf(output, shift);
977 fprintf(output, "LocationSet is NULL !\n");
978 return;
979
980 }
981
982 for (i = 0;i < cur->locNr;i++) {
983 fprintf(output, shift);
984 fprintf(output, "%d : ", i + 1);
985 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
986 }
987}
Daniel Veillard017b1082001-06-21 11:20:21 +0000988#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000989
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000990/**
991 * xmlXPathDebugDumpObject:
992 * @output: the FILE * to dump the output
993 * @cur: the object to inspect
994 * @depth: indentation level
995 *
996 * Dump the content of the object for debugging purposes
997 */
998void
999xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001000 int i;
1001 char shift[100];
1002
Daniel Veillarda82b1822004-11-08 16:24:57 +00001003 if (output == NULL) return;
1004
Owen Taylor3473f882001-02-23 17:55:21 +00001005 for (i = 0;((i < depth) && (i < 25));i++)
1006 shift[2 * i] = shift[2 * i + 1] = ' ';
1007 shift[2 * i] = shift[2 * i + 1] = 0;
1008
Kasimier T. Buchcik97258712006-01-05 12:30:43 +00001009
1010 fprintf(output, shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001011
1012 if (cur == NULL) {
1013 fprintf(output, "Object is empty (NULL)\n");
1014 return;
1015 }
1016 switch(cur->type) {
1017 case XPATH_UNDEFINED:
1018 fprintf(output, "Object is uninitialized\n");
1019 break;
1020 case XPATH_NODESET:
1021 fprintf(output, "Object is a Node Set :\n");
1022 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1023 break;
1024 case XPATH_XSLT_TREE:
1025 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001026 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +00001027 break;
1028 case XPATH_BOOLEAN:
1029 fprintf(output, "Object is a Boolean : ");
1030 if (cur->boolval) fprintf(output, "true\n");
1031 else fprintf(output, "false\n");
1032 break;
1033 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +00001034 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001035 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001036 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001037 break;
1038 case -1:
1039 fprintf(output, "Object is a number : -Infinity\n");
1040 break;
1041 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001042 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001043 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001044 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1045 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001046 } else {
1047 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1048 }
1049 }
Owen Taylor3473f882001-02-23 17:55:21 +00001050 break;
1051 case XPATH_STRING:
1052 fprintf(output, "Object is a string : ");
1053 xmlDebugDumpString(output, cur->stringval);
1054 fprintf(output, "\n");
1055 break;
1056 case XPATH_POINT:
1057 fprintf(output, "Object is a point : index %d in node", cur->index);
1058 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1059 fprintf(output, "\n");
1060 break;
1061 case XPATH_RANGE:
1062 if ((cur->user2 == NULL) ||
1063 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1064 fprintf(output, "Object is a collapsed range :\n");
1065 fprintf(output, shift);
1066 if (cur->index >= 0)
1067 fprintf(output, "index %d in ", cur->index);
1068 fprintf(output, "node\n");
1069 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1070 depth + 1);
1071 } else {
1072 fprintf(output, "Object is a range :\n");
1073 fprintf(output, shift);
1074 fprintf(output, "From ");
1075 if (cur->index >= 0)
1076 fprintf(output, "index %d in ", cur->index);
1077 fprintf(output, "node\n");
1078 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1079 depth + 1);
1080 fprintf(output, shift);
1081 fprintf(output, "To ");
1082 if (cur->index2 >= 0)
1083 fprintf(output, "index %d in ", cur->index2);
1084 fprintf(output, "node\n");
1085 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1086 depth + 1);
1087 fprintf(output, "\n");
1088 }
1089 break;
1090 case XPATH_LOCATIONSET:
1091#if defined(LIBXML_XPTR_ENABLED)
1092 fprintf(output, "Object is a Location Set:\n");
1093 xmlXPathDebugDumpLocationSet(output,
1094 (xmlLocationSetPtr) cur->user, depth);
1095#endif
1096 break;
1097 case XPATH_USERS:
1098 fprintf(output, "Object is user defined\n");
1099 break;
1100 }
1101}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001102
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001103static void
1104xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001105 xmlXPathStepOpPtr op, int depth) {
1106 int i;
1107 char shift[100];
1108
1109 for (i = 0;((i < depth) && (i < 25));i++)
1110 shift[2 * i] = shift[2 * i + 1] = ' ';
1111 shift[2 * i] = shift[2 * i + 1] = 0;
1112
1113 fprintf(output, shift);
1114 if (op == NULL) {
1115 fprintf(output, "Step is NULL\n");
1116 return;
1117 }
1118 switch (op->op) {
1119 case XPATH_OP_END:
1120 fprintf(output, "END"); break;
1121 case XPATH_OP_AND:
1122 fprintf(output, "AND"); break;
1123 case XPATH_OP_OR:
1124 fprintf(output, "OR"); break;
1125 case XPATH_OP_EQUAL:
1126 if (op->value)
1127 fprintf(output, "EQUAL =");
1128 else
1129 fprintf(output, "EQUAL !=");
1130 break;
1131 case XPATH_OP_CMP:
1132 if (op->value)
1133 fprintf(output, "CMP <");
1134 else
1135 fprintf(output, "CMP >");
1136 if (!op->value2)
1137 fprintf(output, "=");
1138 break;
1139 case XPATH_OP_PLUS:
1140 if (op->value == 0)
1141 fprintf(output, "PLUS -");
1142 else if (op->value == 1)
1143 fprintf(output, "PLUS +");
1144 else if (op->value == 2)
1145 fprintf(output, "PLUS unary -");
1146 else if (op->value == 3)
1147 fprintf(output, "PLUS unary - -");
1148 break;
1149 case XPATH_OP_MULT:
1150 if (op->value == 0)
1151 fprintf(output, "MULT *");
1152 else if (op->value == 1)
1153 fprintf(output, "MULT div");
1154 else
1155 fprintf(output, "MULT mod");
1156 break;
1157 case XPATH_OP_UNION:
1158 fprintf(output, "UNION"); break;
1159 case XPATH_OP_ROOT:
1160 fprintf(output, "ROOT"); break;
1161 case XPATH_OP_NODE:
1162 fprintf(output, "NODE"); break;
1163 case XPATH_OP_RESET:
1164 fprintf(output, "RESET"); break;
1165 case XPATH_OP_SORT:
1166 fprintf(output, "SORT"); break;
1167 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +00001168 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1169 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1170 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001171 const xmlChar *prefix = op->value4;
1172 const xmlChar *name = op->value5;
1173
1174 fprintf(output, "COLLECT ");
1175 switch (axis) {
1176 case AXIS_ANCESTOR:
1177 fprintf(output, " 'ancestors' "); break;
1178 case AXIS_ANCESTOR_OR_SELF:
1179 fprintf(output, " 'ancestors-or-self' "); break;
1180 case AXIS_ATTRIBUTE:
1181 fprintf(output, " 'attributes' "); break;
1182 case AXIS_CHILD:
1183 fprintf(output, " 'child' "); break;
1184 case AXIS_DESCENDANT:
1185 fprintf(output, " 'descendant' "); break;
1186 case AXIS_DESCENDANT_OR_SELF:
1187 fprintf(output, " 'descendant-or-self' "); break;
1188 case AXIS_FOLLOWING:
1189 fprintf(output, " 'following' "); break;
1190 case AXIS_FOLLOWING_SIBLING:
1191 fprintf(output, " 'following-siblings' "); break;
1192 case AXIS_NAMESPACE:
1193 fprintf(output, " 'namespace' "); break;
1194 case AXIS_PARENT:
1195 fprintf(output, " 'parent' "); break;
1196 case AXIS_PRECEDING:
1197 fprintf(output, " 'preceding' "); break;
1198 case AXIS_PRECEDING_SIBLING:
1199 fprintf(output, " 'preceding-sibling' "); break;
1200 case AXIS_SELF:
1201 fprintf(output, " 'self' "); break;
1202 }
1203 switch (test) {
1204 case NODE_TEST_NONE:
1205 fprintf(output, "'none' "); break;
1206 case NODE_TEST_TYPE:
1207 fprintf(output, "'type' "); break;
1208 case NODE_TEST_PI:
1209 fprintf(output, "'PI' "); break;
1210 case NODE_TEST_ALL:
1211 fprintf(output, "'all' "); break;
1212 case NODE_TEST_NS:
1213 fprintf(output, "'namespace' "); break;
1214 case NODE_TEST_NAME:
1215 fprintf(output, "'name' "); break;
1216 }
1217 switch (type) {
1218 case NODE_TYPE_NODE:
1219 fprintf(output, "'node' "); break;
1220 case NODE_TYPE_COMMENT:
1221 fprintf(output, "'comment' "); break;
1222 case NODE_TYPE_TEXT:
1223 fprintf(output, "'text' "); break;
1224 case NODE_TYPE_PI:
1225 fprintf(output, "'PI' "); break;
1226 }
1227 if (prefix != NULL)
1228 fprintf(output, "%s:", prefix);
1229 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001230 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001231 break;
1232
1233 }
1234 case XPATH_OP_VALUE: {
1235 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1236
1237 fprintf(output, "ELEM ");
1238 xmlXPathDebugDumpObject(output, object, 0);
1239 goto finish;
1240 }
1241 case XPATH_OP_VARIABLE: {
1242 const xmlChar *prefix = op->value5;
1243 const xmlChar *name = op->value4;
1244
1245 if (prefix != NULL)
1246 fprintf(output, "VARIABLE %s:%s", prefix, name);
1247 else
1248 fprintf(output, "VARIABLE %s", name);
1249 break;
1250 }
1251 case XPATH_OP_FUNCTION: {
1252 int nbargs = op->value;
1253 const xmlChar *prefix = op->value5;
1254 const xmlChar *name = op->value4;
1255
1256 if (prefix != NULL)
1257 fprintf(output, "FUNCTION %s:%s(%d args)",
1258 prefix, name, nbargs);
1259 else
1260 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1261 break;
1262 }
1263 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1264 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001265 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001266#ifdef LIBXML_XPTR_ENABLED
1267 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1268#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001269 default:
1270 fprintf(output, "UNKNOWN %d\n", op->op); return;
1271 }
1272 fprintf(output, "\n");
1273finish:
1274 if (op->ch1 >= 0)
1275 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1276 if (op->ch2 >= 0)
1277 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1278}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001279
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001280/**
1281 * xmlXPathDebugDumpCompExpr:
1282 * @output: the FILE * for the output
1283 * @comp: the precompiled XPath expression
1284 * @depth: the indentation level.
1285 *
1286 * Dumps the tree of the compiled XPath expression.
1287 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001288void
1289xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1290 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001291 int i;
1292 char shift[100];
1293
Daniel Veillarda82b1822004-11-08 16:24:57 +00001294 if ((output == NULL) || (comp == NULL)) return;
1295
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001296 for (i = 0;((i < depth) && (i < 25));i++)
1297 shift[2 * i] = shift[2 * i + 1] = ' ';
1298 shift[2 * i] = shift[2 * i + 1] = 0;
1299
1300 fprintf(output, shift);
1301
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001302 fprintf(output, "Compiled Expression : %d elements\n",
1303 comp->nbStep);
1304 i = comp->last;
1305 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1306}
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001307
1308#ifdef XP_DEBUG_OBJ_USAGE
1309
1310/*
1311* XPath object usage related debugging variables.
1312*/
1313static int xmlXPathDebugObjCounterUndefined = 0;
1314static int xmlXPathDebugObjCounterNodeset = 0;
1315static int xmlXPathDebugObjCounterBool = 0;
1316static int xmlXPathDebugObjCounterNumber = 0;
1317static int xmlXPathDebugObjCounterString = 0;
1318static int xmlXPathDebugObjCounterPoint = 0;
1319static int xmlXPathDebugObjCounterRange = 0;
1320static int xmlXPathDebugObjCounterLocset = 0;
1321static int xmlXPathDebugObjCounterUsers = 0;
1322static int xmlXPathDebugObjCounterXSLTTree = 0;
1323static int xmlXPathDebugObjCounterAll = 0;
1324
1325static int xmlXPathDebugObjTotalUndefined = 0;
1326static int xmlXPathDebugObjTotalNodeset = 0;
1327static int xmlXPathDebugObjTotalBool = 0;
1328static int xmlXPathDebugObjTotalNumber = 0;
1329static int xmlXPathDebugObjTotalString = 0;
1330static int xmlXPathDebugObjTotalPoint = 0;
1331static int xmlXPathDebugObjTotalRange = 0;
1332static int xmlXPathDebugObjTotalLocset = 0;
1333static int xmlXPathDebugObjTotalUsers = 0;
1334static int xmlXPathDebugObjTotalXSLTTree = 0;
1335static int xmlXPathDebugObjTotalAll = 0;
1336
1337static int xmlXPathDebugObjMaxUndefined = 0;
1338static int xmlXPathDebugObjMaxNodeset = 0;
1339static int xmlXPathDebugObjMaxBool = 0;
1340static int xmlXPathDebugObjMaxNumber = 0;
1341static int xmlXPathDebugObjMaxString = 0;
1342static int xmlXPathDebugObjMaxPoint = 0;
1343static int xmlXPathDebugObjMaxRange = 0;
1344static int xmlXPathDebugObjMaxLocset = 0;
1345static int xmlXPathDebugObjMaxUsers = 0;
1346static int xmlXPathDebugObjMaxXSLTTree = 0;
1347static int xmlXPathDebugObjMaxAll = 0;
1348
1349/* REVISIT TODO: Make this static when committing */
1350static void
1351xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1352{
1353 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001354 if (ctxt->cache != NULL) {
1355 xmlXPathContextCachePtr cache =
1356 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001357
1358 cache->dbgCachedAll = 0;
1359 cache->dbgCachedNodeset = 0;
1360 cache->dbgCachedString = 0;
1361 cache->dbgCachedBool = 0;
1362 cache->dbgCachedNumber = 0;
1363 cache->dbgCachedPoint = 0;
1364 cache->dbgCachedRange = 0;
1365 cache->dbgCachedLocset = 0;
1366 cache->dbgCachedUsers = 0;
1367 cache->dbgCachedXSLTTree = 0;
1368 cache->dbgCachedUndefined = 0;
1369
1370 cache->dbgReusedAll = 0;
1371 cache->dbgReusedNodeset = 0;
1372 cache->dbgReusedString = 0;
1373 cache->dbgReusedBool = 0;
1374 cache->dbgReusedNumber = 0;
1375 cache->dbgReusedPoint = 0;
1376 cache->dbgReusedRange = 0;
1377 cache->dbgReusedLocset = 0;
1378 cache->dbgReusedUsers = 0;
1379 cache->dbgReusedXSLTTree = 0;
1380 cache->dbgReusedUndefined = 0;
1381 }
1382 }
1383
1384 xmlXPathDebugObjCounterUndefined = 0;
1385 xmlXPathDebugObjCounterNodeset = 0;
1386 xmlXPathDebugObjCounterBool = 0;
1387 xmlXPathDebugObjCounterNumber = 0;
1388 xmlXPathDebugObjCounterString = 0;
1389 xmlXPathDebugObjCounterPoint = 0;
1390 xmlXPathDebugObjCounterRange = 0;
1391 xmlXPathDebugObjCounterLocset = 0;
1392 xmlXPathDebugObjCounterUsers = 0;
1393 xmlXPathDebugObjCounterXSLTTree = 0;
1394 xmlXPathDebugObjCounterAll = 0;
1395
1396 xmlXPathDebugObjTotalUndefined = 0;
1397 xmlXPathDebugObjTotalNodeset = 0;
1398 xmlXPathDebugObjTotalBool = 0;
1399 xmlXPathDebugObjTotalNumber = 0;
1400 xmlXPathDebugObjTotalString = 0;
1401 xmlXPathDebugObjTotalPoint = 0;
1402 xmlXPathDebugObjTotalRange = 0;
1403 xmlXPathDebugObjTotalLocset = 0;
1404 xmlXPathDebugObjTotalUsers = 0;
1405 xmlXPathDebugObjTotalXSLTTree = 0;
1406 xmlXPathDebugObjTotalAll = 0;
1407
1408 xmlXPathDebugObjMaxUndefined = 0;
1409 xmlXPathDebugObjMaxNodeset = 0;
1410 xmlXPathDebugObjMaxBool = 0;
1411 xmlXPathDebugObjMaxNumber = 0;
1412 xmlXPathDebugObjMaxString = 0;
1413 xmlXPathDebugObjMaxPoint = 0;
1414 xmlXPathDebugObjMaxRange = 0;
1415 xmlXPathDebugObjMaxLocset = 0;
1416 xmlXPathDebugObjMaxUsers = 0;
1417 xmlXPathDebugObjMaxXSLTTree = 0;
1418 xmlXPathDebugObjMaxAll = 0;
1419
1420}
1421
1422static void
1423xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1424 xmlXPathObjectType objType)
1425{
1426 int isCached = 0;
1427
1428 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001429 if (ctxt->cache != NULL) {
1430 xmlXPathContextCachePtr cache =
1431 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001432
1433 isCached = 1;
1434
1435 cache->dbgReusedAll++;
1436 switch (objType) {
1437 case XPATH_UNDEFINED:
1438 cache->dbgReusedUndefined++;
1439 break;
1440 case XPATH_NODESET:
1441 cache->dbgReusedNodeset++;
1442 break;
1443 case XPATH_BOOLEAN:
1444 cache->dbgReusedBool++;
1445 break;
1446 case XPATH_NUMBER:
1447 cache->dbgReusedNumber++;
1448 break;
1449 case XPATH_STRING:
1450 cache->dbgReusedString++;
1451 break;
1452 case XPATH_POINT:
1453 cache->dbgReusedPoint++;
1454 break;
1455 case XPATH_RANGE:
1456 cache->dbgReusedRange++;
1457 break;
1458 case XPATH_LOCATIONSET:
1459 cache->dbgReusedLocset++;
1460 break;
1461 case XPATH_USERS:
1462 cache->dbgReusedUsers++;
1463 break;
1464 case XPATH_XSLT_TREE:
1465 cache->dbgReusedXSLTTree++;
1466 break;
1467 default:
1468 break;
1469 }
1470 }
1471 }
1472
1473 switch (objType) {
1474 case XPATH_UNDEFINED:
1475 if (! isCached)
1476 xmlXPathDebugObjTotalUndefined++;
1477 xmlXPathDebugObjCounterUndefined++;
1478 if (xmlXPathDebugObjCounterUndefined >
1479 xmlXPathDebugObjMaxUndefined)
1480 xmlXPathDebugObjMaxUndefined =
1481 xmlXPathDebugObjCounterUndefined;
1482 break;
1483 case XPATH_NODESET:
1484 if (! isCached)
1485 xmlXPathDebugObjTotalNodeset++;
1486 xmlXPathDebugObjCounterNodeset++;
1487 if (xmlXPathDebugObjCounterNodeset >
1488 xmlXPathDebugObjMaxNodeset)
1489 xmlXPathDebugObjMaxNodeset =
1490 xmlXPathDebugObjCounterNodeset;
1491 break;
1492 case XPATH_BOOLEAN:
1493 if (! isCached)
1494 xmlXPathDebugObjTotalBool++;
1495 xmlXPathDebugObjCounterBool++;
1496 if (xmlXPathDebugObjCounterBool >
1497 xmlXPathDebugObjMaxBool)
1498 xmlXPathDebugObjMaxBool =
1499 xmlXPathDebugObjCounterBool;
1500 break;
1501 case XPATH_NUMBER:
1502 if (! isCached)
1503 xmlXPathDebugObjTotalNumber++;
1504 xmlXPathDebugObjCounterNumber++;
1505 if (xmlXPathDebugObjCounterNumber >
1506 xmlXPathDebugObjMaxNumber)
1507 xmlXPathDebugObjMaxNumber =
1508 xmlXPathDebugObjCounterNumber;
1509 break;
1510 case XPATH_STRING:
1511 if (! isCached)
1512 xmlXPathDebugObjTotalString++;
1513 xmlXPathDebugObjCounterString++;
1514 if (xmlXPathDebugObjCounterString >
1515 xmlXPathDebugObjMaxString)
1516 xmlXPathDebugObjMaxString =
1517 xmlXPathDebugObjCounterString;
1518 break;
1519 case XPATH_POINT:
1520 if (! isCached)
1521 xmlXPathDebugObjTotalPoint++;
1522 xmlXPathDebugObjCounterPoint++;
1523 if (xmlXPathDebugObjCounterPoint >
1524 xmlXPathDebugObjMaxPoint)
1525 xmlXPathDebugObjMaxPoint =
1526 xmlXPathDebugObjCounterPoint;
1527 break;
1528 case XPATH_RANGE:
1529 if (! isCached)
1530 xmlXPathDebugObjTotalRange++;
1531 xmlXPathDebugObjCounterRange++;
1532 if (xmlXPathDebugObjCounterRange >
1533 xmlXPathDebugObjMaxRange)
1534 xmlXPathDebugObjMaxRange =
1535 xmlXPathDebugObjCounterRange;
1536 break;
1537 case XPATH_LOCATIONSET:
1538 if (! isCached)
1539 xmlXPathDebugObjTotalLocset++;
1540 xmlXPathDebugObjCounterLocset++;
1541 if (xmlXPathDebugObjCounterLocset >
1542 xmlXPathDebugObjMaxLocset)
1543 xmlXPathDebugObjMaxLocset =
1544 xmlXPathDebugObjCounterLocset;
1545 break;
1546 case XPATH_USERS:
1547 if (! isCached)
1548 xmlXPathDebugObjTotalUsers++;
1549 xmlXPathDebugObjCounterUsers++;
1550 if (xmlXPathDebugObjCounterUsers >
1551 xmlXPathDebugObjMaxUsers)
1552 xmlXPathDebugObjMaxUsers =
1553 xmlXPathDebugObjCounterUsers;
1554 break;
1555 case XPATH_XSLT_TREE:
1556 if (! isCached)
1557 xmlXPathDebugObjTotalXSLTTree++;
1558 xmlXPathDebugObjCounterXSLTTree++;
1559 if (xmlXPathDebugObjCounterXSLTTree >
1560 xmlXPathDebugObjMaxXSLTTree)
1561 xmlXPathDebugObjMaxXSLTTree =
1562 xmlXPathDebugObjCounterXSLTTree;
1563 break;
1564 default:
1565 break;
1566 }
1567 if (! isCached)
1568 xmlXPathDebugObjTotalAll++;
1569 xmlXPathDebugObjCounterAll++;
1570 if (xmlXPathDebugObjCounterAll >
1571 xmlXPathDebugObjMaxAll)
1572 xmlXPathDebugObjMaxAll =
1573 xmlXPathDebugObjCounterAll;
1574}
1575
1576static void
1577xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1578 xmlXPathObjectType objType)
1579{
1580 int isCached = 0;
1581
1582 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001583 if (ctxt->cache != NULL) {
1584 xmlXPathContextCachePtr cache =
1585 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001586
1587 isCached = 1;
1588
1589 cache->dbgCachedAll++;
1590 switch (objType) {
1591 case XPATH_UNDEFINED:
1592 cache->dbgCachedUndefined++;
1593 break;
1594 case XPATH_NODESET:
1595 cache->dbgCachedNodeset++;
1596 break;
1597 case XPATH_BOOLEAN:
1598 cache->dbgCachedBool++;
1599 break;
1600 case XPATH_NUMBER:
1601 cache->dbgCachedNumber++;
1602 break;
1603 case XPATH_STRING:
1604 cache->dbgCachedString++;
1605 break;
1606 case XPATH_POINT:
1607 cache->dbgCachedPoint++;
1608 break;
1609 case XPATH_RANGE:
1610 cache->dbgCachedRange++;
1611 break;
1612 case XPATH_LOCATIONSET:
1613 cache->dbgCachedLocset++;
1614 break;
1615 case XPATH_USERS:
1616 cache->dbgCachedUsers++;
1617 break;
1618 case XPATH_XSLT_TREE:
1619 cache->dbgCachedXSLTTree++;
1620 break;
1621 default:
1622 break;
1623 }
1624
1625 }
1626 }
1627 switch (objType) {
1628 case XPATH_UNDEFINED:
1629 xmlXPathDebugObjCounterUndefined--;
1630 break;
1631 case XPATH_NODESET:
1632 xmlXPathDebugObjCounterNodeset--;
1633 break;
1634 case XPATH_BOOLEAN:
1635 xmlXPathDebugObjCounterBool--;
1636 break;
1637 case XPATH_NUMBER:
1638 xmlXPathDebugObjCounterNumber--;
1639 break;
1640 case XPATH_STRING:
1641 xmlXPathDebugObjCounterString--;
1642 break;
1643 case XPATH_POINT:
1644 xmlXPathDebugObjCounterPoint--;
1645 break;
1646 case XPATH_RANGE:
1647 xmlXPathDebugObjCounterRange--;
1648 break;
1649 case XPATH_LOCATIONSET:
1650 xmlXPathDebugObjCounterLocset--;
1651 break;
1652 case XPATH_USERS:
1653 xmlXPathDebugObjCounterUsers--;
1654 break;
1655 case XPATH_XSLT_TREE:
1656 xmlXPathDebugObjCounterXSLTTree--;
1657 break;
1658 default:
1659 break;
1660 }
1661 xmlXPathDebugObjCounterAll--;
1662}
1663
1664/* REVISIT TODO: Make this static when committing */
1665static void
1666xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
1667{
1668 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
1669 reqXSLTTree, reqUndefined;
1670 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
1671 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
1672 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
1673 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
1674 int leftObjs = xmlXPathDebugObjCounterAll;
1675
1676 reqAll = xmlXPathDebugObjTotalAll;
1677 reqNodeset = xmlXPathDebugObjTotalNodeset;
1678 reqString = xmlXPathDebugObjTotalString;
1679 reqBool = xmlXPathDebugObjTotalBool;
1680 reqNumber = xmlXPathDebugObjTotalNumber;
1681 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
1682 reqUndefined = xmlXPathDebugObjTotalUndefined;
1683
1684 printf("# XPath object usage:\n");
1685
1686 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001687 if (ctxt->cache != NULL) {
1688 xmlXPathContextCachePtr cache =
1689 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001690
1691 reAll = cache->dbgReusedAll;
1692 reqAll += reAll;
1693 reNodeset = cache->dbgReusedNodeset;
1694 reqNodeset += reNodeset;
1695 reString = cache->dbgReusedString;
1696 reqString += reString;
1697 reBool = cache->dbgReusedBool;
1698 reqBool += reBool;
1699 reNumber = cache->dbgReusedNumber;
1700 reqNumber += reNumber;
1701 reXSLTTree = cache->dbgReusedXSLTTree;
1702 reqXSLTTree += reXSLTTree;
1703 reUndefined = cache->dbgReusedUndefined;
1704 reqUndefined += reUndefined;
1705
1706 caAll = cache->dbgCachedAll;
1707 caBool = cache->dbgCachedBool;
1708 caNodeset = cache->dbgCachedNodeset;
1709 caString = cache->dbgCachedString;
1710 caNumber = cache->dbgCachedNumber;
1711 caXSLTTree = cache->dbgCachedXSLTTree;
1712 caUndefined = cache->dbgCachedUndefined;
1713
1714 if (cache->nodesetObjs)
1715 leftObjs -= cache->nodesetObjs->number;
1716 if (cache->stringObjs)
1717 leftObjs -= cache->stringObjs->number;
1718 if (cache->booleanObjs)
1719 leftObjs -= cache->booleanObjs->number;
1720 if (cache->numberObjs)
1721 leftObjs -= cache->numberObjs->number;
1722 if (cache->miscObjs)
1723 leftObjs -= cache->miscObjs->number;
1724 }
1725 }
1726
1727 printf("# all\n");
1728 printf("# total : %d\n", reqAll);
1729 printf("# left : %d\n", leftObjs);
1730 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
1731 printf("# reused : %d\n", reAll);
1732 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
1733
1734 printf("# node-sets\n");
1735 printf("# total : %d\n", reqNodeset);
1736 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
1737 printf("# reused : %d\n", reNodeset);
1738 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
1739
1740 printf("# strings\n");
1741 printf("# total : %d\n", reqString);
1742 printf("# created: %d\n", xmlXPathDebugObjTotalString);
1743 printf("# reused : %d\n", reString);
1744 printf("# max : %d\n", xmlXPathDebugObjMaxString);
1745
1746 printf("# booleans\n");
1747 printf("# total : %d\n", reqBool);
1748 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
1749 printf("# reused : %d\n", reBool);
1750 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
1751
1752 printf("# numbers\n");
1753 printf("# total : %d\n", reqNumber);
1754 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
1755 printf("# reused : %d\n", reNumber);
1756 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
1757
1758 printf("# XSLT result tree fragments\n");
1759 printf("# total : %d\n", reqXSLTTree);
1760 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
1761 printf("# reused : %d\n", reXSLTTree);
1762 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
1763
1764 printf("# undefined\n");
1765 printf("# total : %d\n", reqUndefined);
1766 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
1767 printf("# reused : %d\n", reUndefined);
1768 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
1769
1770}
1771
1772#endif /* XP_DEBUG_OBJ_USAGE */
1773
Daniel Veillard017b1082001-06-21 11:20:21 +00001774#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001775
1776/************************************************************************
1777 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001778 * XPath object caching *
1779 * *
1780 ************************************************************************/
1781
1782/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001783 * xmlXPathNewCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001784 *
1785 * Create a new object cache
1786 *
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001787 * Returns the xmlXPathCache just allocated.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001788 */
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001789static xmlXPathContextCachePtr
1790xmlXPathNewCache(void)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001791{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001792 xmlXPathContextCachePtr ret;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001793
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001794 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001795 if (ret == NULL) {
1796 xmlXPathErrMemory(NULL, "creating object cache\n");
1797 return(NULL);
1798 }
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001799 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001800 ret->maxNodeset = 100;
1801 ret->maxString = 100;
1802 ret->maxBoolean = 100;
1803 ret->maxNumber = 100;
1804 ret->maxMisc = 100;
1805 return(ret);
1806}
1807
1808static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001809xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001810{
1811 int i;
1812 xmlXPathObjectPtr obj;
1813
1814 if (list == NULL)
1815 return;
1816
1817 for (i = 0; i < list->number; i++) {
1818 obj = list->items[i];
1819 /*
1820 * Note that it is already assured that we don't need to
1821 * look out for namespace nodes in the node-set.
1822 */
1823 if (obj->nodesetval != NULL) {
1824 if (obj->nodesetval->nodeTab != NULL)
1825 xmlFree(obj->nodesetval->nodeTab);
1826 xmlFree(obj->nodesetval);
1827 }
1828 xmlFree(obj);
1829#ifdef XP_DEBUG_OBJ_USAGE
1830 xmlXPathDebugObjCounterAll--;
1831#endif
1832 }
1833 xmlPointerListFree(list);
1834}
1835
1836static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001837xmlXPathFreeCache(xmlXPathContextCachePtr cache)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001838{
1839 if (cache == NULL)
1840 return;
1841 if (cache->nodesetObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001842 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001843 if (cache->stringObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001844 xmlXPathCacheFreeObjectList(cache->stringObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001845 if (cache->booleanObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001846 xmlXPathCacheFreeObjectList(cache->booleanObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001847 if (cache->numberObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001848 xmlXPathCacheFreeObjectList(cache->numberObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001849 if (cache->miscObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001850 xmlXPathCacheFreeObjectList(cache->miscObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001851 xmlFree(cache);
1852}
1853
1854/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001855 * xmlXPathContextSetCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001856 *
1857 * @ctxt: the XPath context
1858 * @active: enables/disables (creates/frees) the cache
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001859 * @value: a value with semantics dependant on @options
1860 * @options: options (currently only the value 0 is used)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001861 *
1862 * Creates/frees an object cache on the XPath context.
1863 * If activates XPath objects (xmlXPathObject) will be cached internally
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001864 * to be reused.
1865 * @options:
1866 * 0: This will set the XPath object caching:
1867 * @value:
1868 * This will set the maximum number of XPath objects
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001869 * to be cached per slot
1870 * There are 5 slots for: node-set, string, number, boolean, and
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001871 * misc objects. Use <0 for the default number (100).
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001872 * Other values for @options have currently no effect.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001873 *
1874 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1875 */
1876int
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001877xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1878 int active,
1879 int value,
1880 int options)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001881{
1882 if (ctxt == NULL)
1883 return(-1);
1884 if (active) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001885 xmlXPathContextCachePtr cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001886
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001887 if (ctxt->cache == NULL) {
1888 ctxt->cache = xmlXPathNewCache();
1889 if (ctxt->cache == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001890 return(-1);
1891 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001892 cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001893 if (options == 0) {
1894 if (value < 0)
1895 value = 100;
1896 cache->maxNodeset = value;
1897 cache->maxString = value;
1898 cache->maxNumber = value;
1899 cache->maxBoolean = value;
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001900 cache->maxMisc = value;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001901 }
1902 } else if (ctxt->cache != NULL) {
1903 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1904 ctxt->cache = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001905 }
1906 return(0);
1907}
1908
1909/**
1910 * xmlXPathCacheWrapNodeSet:
1911 * @ctxt: the XPath context
1912 * @val: the NodePtr value
1913 *
1914 * This is the cached version of xmlXPathWrapNodeSet().
1915 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1916 *
1917 * Returns the created or reused object.
1918 */
1919static xmlXPathObjectPtr
1920xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
1921{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001922 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1923 xmlXPathContextCachePtr cache =
1924 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001925
1926 if ((cache->miscObjs != NULL) &&
1927 (cache->miscObjs->number != 0))
1928 {
1929 xmlXPathObjectPtr ret;
1930
1931 ret = (xmlXPathObjectPtr)
1932 cache->miscObjs->items[--cache->miscObjs->number];
1933 ret->type = XPATH_NODESET;
1934 ret->nodesetval = val;
1935#ifdef XP_DEBUG_OBJ_USAGE
1936 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
1937#endif
1938 return(ret);
1939 }
1940 }
1941
1942 return(xmlXPathWrapNodeSet(val));
1943
1944}
1945
1946/**
1947 * xmlXPathCacheWrapString:
1948 * @ctxt: the XPath context
1949 * @val: the xmlChar * value
1950 *
1951 * This is the cached version of xmlXPathWrapString().
1952 * Wraps the @val string into an XPath object.
1953 *
1954 * Returns the created or reused object.
1955 */
1956static xmlXPathObjectPtr
1957xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
1958{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001959 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1960 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001961
1962 if ((cache->stringObjs != NULL) &&
1963 (cache->stringObjs->number != 0))
1964 {
1965
1966 xmlXPathObjectPtr ret;
1967
1968 ret = (xmlXPathObjectPtr)
1969 cache->stringObjs->items[--cache->stringObjs->number];
1970 ret->type = XPATH_STRING;
1971 ret->stringval = val;
1972#ifdef XP_DEBUG_OBJ_USAGE
1973 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1974#endif
1975 return(ret);
1976 } else if ((cache->miscObjs != NULL) &&
1977 (cache->miscObjs->number != 0))
1978 {
1979 xmlXPathObjectPtr ret;
1980 /*
1981 * Fallback to misc-cache.
1982 */
1983 ret = (xmlXPathObjectPtr)
1984 cache->miscObjs->items[--cache->miscObjs->number];
1985
1986 ret->type = XPATH_STRING;
1987 ret->stringval = val;
1988#ifdef XP_DEBUG_OBJ_USAGE
1989 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1990#endif
1991 return(ret);
1992 }
1993 }
1994 return(xmlXPathWrapString(val));
1995}
1996
1997/**
1998 * xmlXPathCacheNewNodeSet:
1999 * @ctxt: the XPath context
2000 * @val: the NodePtr value
2001 *
2002 * This is the cached version of xmlXPathNewNodeSet().
2003 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2004 * it with the single Node @val
2005 *
2006 * Returns the created or reused object.
2007 */
2008static xmlXPathObjectPtr
2009xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2010{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002011 if ((ctxt != NULL) && (ctxt->cache)) {
2012 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002013
2014 if ((cache->nodesetObjs != NULL) &&
2015 (cache->nodesetObjs->number != 0))
2016 {
2017 xmlXPathObjectPtr ret;
2018 /*
2019 * Use the nodset-cache.
2020 */
2021 ret = (xmlXPathObjectPtr)
2022 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2023 ret->type = XPATH_NODESET;
2024 ret->boolval = 0;
2025 if (val) {
2026 if ((ret->nodesetval->nodeMax == 0) ||
2027 (val->type == XML_NAMESPACE_DECL))
2028 {
2029 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2030 } else {
2031 ret->nodesetval->nodeTab[0] = val;
2032 ret->nodesetval->nodeNr = 1;
2033 }
2034 }
2035#ifdef XP_DEBUG_OBJ_USAGE
2036 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2037#endif
2038 return(ret);
2039 } else if ((cache->miscObjs != NULL) &&
2040 (cache->miscObjs->number != 0))
2041 {
2042 xmlXPathObjectPtr ret;
2043 /*
2044 * Fallback to misc-cache.
2045 */
2046
2047 ret = (xmlXPathObjectPtr)
2048 cache->miscObjs->items[--cache->miscObjs->number];
2049
2050 ret->type = XPATH_NODESET;
2051 ret->boolval = 0;
2052 ret->nodesetval = xmlXPathNodeSetCreate(val);
2053#ifdef XP_DEBUG_OBJ_USAGE
2054 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2055#endif
2056 return(ret);
2057 }
2058 }
2059 return(xmlXPathNewNodeSet(val));
2060}
2061
2062/**
2063 * xmlXPathCacheNewCString:
2064 * @ctxt: the XPath context
2065 * @val: the char * value
2066 *
2067 * This is the cached version of xmlXPathNewCString().
2068 * Acquire an xmlXPathObjectPtr of type string and of value @val
2069 *
2070 * Returns the created or reused object.
2071 */
2072static xmlXPathObjectPtr
2073xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2074{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002075 if ((ctxt != NULL) && (ctxt->cache)) {
2076 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002077
2078 if ((cache->stringObjs != NULL) &&
2079 (cache->stringObjs->number != 0))
2080 {
2081 xmlXPathObjectPtr ret;
2082
2083 ret = (xmlXPathObjectPtr)
2084 cache->stringObjs->items[--cache->stringObjs->number];
2085
2086 ret->type = XPATH_STRING;
2087 ret->stringval = xmlStrdup(BAD_CAST val);
2088#ifdef XP_DEBUG_OBJ_USAGE
2089 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2090#endif
2091 return(ret);
2092 } else if ((cache->miscObjs != NULL) &&
2093 (cache->miscObjs->number != 0))
2094 {
2095 xmlXPathObjectPtr ret;
2096
2097 ret = (xmlXPathObjectPtr)
2098 cache->miscObjs->items[--cache->miscObjs->number];
2099
2100 ret->type = XPATH_STRING;
2101 ret->stringval = xmlStrdup(BAD_CAST val);
2102#ifdef XP_DEBUG_OBJ_USAGE
2103 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2104#endif
2105 return(ret);
2106 }
2107 }
2108 return(xmlXPathNewCString(val));
2109}
2110
2111/**
2112 * xmlXPathCacheNewString:
2113 * @ctxt: the XPath context
2114 * @val: the xmlChar * value
2115 *
2116 * This is the cached version of xmlXPathNewString().
2117 * Acquire an xmlXPathObjectPtr of type string and of value @val
2118 *
2119 * Returns the created or reused object.
2120 */
2121static xmlXPathObjectPtr
2122xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2123{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002124 if ((ctxt != NULL) && (ctxt->cache)) {
2125 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002126
2127 if ((cache->stringObjs != NULL) &&
2128 (cache->stringObjs->number != 0))
2129 {
2130 xmlXPathObjectPtr ret;
2131
2132 ret = (xmlXPathObjectPtr)
2133 cache->stringObjs->items[--cache->stringObjs->number];
2134 ret->type = XPATH_STRING;
2135 if (val != NULL)
2136 ret->stringval = xmlStrdup(val);
2137 else
2138 ret->stringval = xmlStrdup((const xmlChar *)"");
2139#ifdef XP_DEBUG_OBJ_USAGE
2140 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2141#endif
2142 return(ret);
2143 } else if ((cache->miscObjs != NULL) &&
2144 (cache->miscObjs->number != 0))
2145 {
2146 xmlXPathObjectPtr ret;
2147
2148 ret = (xmlXPathObjectPtr)
2149 cache->miscObjs->items[--cache->miscObjs->number];
2150
2151 ret->type = XPATH_STRING;
2152 if (val != NULL)
2153 ret->stringval = xmlStrdup(val);
2154 else
2155 ret->stringval = xmlStrdup((const xmlChar *)"");
2156#ifdef XP_DEBUG_OBJ_USAGE
2157 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2158#endif
2159 return(ret);
2160 }
2161 }
2162 return(xmlXPathNewString(val));
2163}
2164
2165/**
2166 * xmlXPathCacheNewBoolean:
2167 * @ctxt: the XPath context
2168 * @val: the boolean value
2169 *
2170 * This is the cached version of xmlXPathNewBoolean().
2171 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2172 *
2173 * Returns the created or reused object.
2174 */
2175static xmlXPathObjectPtr
2176xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2177{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002178 if ((ctxt != NULL) && (ctxt->cache)) {
2179 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002180
2181 if ((cache->booleanObjs != NULL) &&
2182 (cache->booleanObjs->number != 0))
2183 {
2184 xmlXPathObjectPtr ret;
2185
2186 ret = (xmlXPathObjectPtr)
2187 cache->booleanObjs->items[--cache->booleanObjs->number];
2188 ret->type = XPATH_BOOLEAN;
2189 ret->boolval = (val != 0);
2190#ifdef XP_DEBUG_OBJ_USAGE
2191 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2192#endif
2193 return(ret);
2194 } else if ((cache->miscObjs != NULL) &&
2195 (cache->miscObjs->number != 0))
2196 {
2197 xmlXPathObjectPtr ret;
2198
2199 ret = (xmlXPathObjectPtr)
2200 cache->miscObjs->items[--cache->miscObjs->number];
2201
2202 ret->type = XPATH_BOOLEAN;
2203 ret->boolval = (val != 0);
2204#ifdef XP_DEBUG_OBJ_USAGE
2205 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2206#endif
2207 return(ret);
2208 }
2209 }
2210 return(xmlXPathNewBoolean(val));
2211}
2212
2213/**
2214 * xmlXPathCacheNewFloat:
2215 * @ctxt: the XPath context
2216 * @val: the double value
2217 *
2218 * This is the cached version of xmlXPathNewFloat().
2219 * Acquires an xmlXPathObjectPtr of type double and of value @val
2220 *
2221 * Returns the created or reused object.
2222 */
2223static xmlXPathObjectPtr
2224xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2225{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002226 if ((ctxt != NULL) && (ctxt->cache)) {
2227 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002228
2229 if ((cache->numberObjs != NULL) &&
2230 (cache->numberObjs->number != 0))
2231 {
2232 xmlXPathObjectPtr ret;
2233
2234 ret = (xmlXPathObjectPtr)
2235 cache->numberObjs->items[--cache->numberObjs->number];
2236 ret->type = XPATH_NUMBER;
2237 ret->floatval = val;
2238#ifdef XP_DEBUG_OBJ_USAGE
2239 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2240#endif
2241 return(ret);
2242 } else if ((cache->miscObjs != NULL) &&
2243 (cache->miscObjs->number != 0))
2244 {
2245 xmlXPathObjectPtr ret;
2246
2247 ret = (xmlXPathObjectPtr)
2248 cache->miscObjs->items[--cache->miscObjs->number];
2249
2250 ret->type = XPATH_NUMBER;
2251 ret->floatval = val;
2252#ifdef XP_DEBUG_OBJ_USAGE
2253 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2254#endif
2255 return(ret);
2256 }
2257 }
2258 return(xmlXPathNewFloat(val));
2259}
2260
2261/**
2262 * xmlXPathCacheConvertString:
2263 * @ctxt: the XPath context
2264 * @val: an XPath object
2265 *
2266 * This is the cached version of xmlXPathConvertString().
2267 * Converts an existing object to its string() equivalent
2268 *
2269 * Returns a created or reused object, the old one is freed (cached)
2270 * (or the operation is done directly on @val)
2271 */
2272
2273static xmlXPathObjectPtr
2274xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2275 xmlChar *res = NULL;
2276
2277 if (val == NULL)
2278 return(xmlXPathCacheNewCString(ctxt, ""));
2279
2280 switch (val->type) {
2281 case XPATH_UNDEFINED:
2282#ifdef DEBUG_EXPR
2283 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2284#endif
2285 break;
2286 case XPATH_NODESET:
2287 case XPATH_XSLT_TREE:
2288 res = xmlXPathCastNodeSetToString(val->nodesetval);
2289 break;
2290 case XPATH_STRING:
2291 return(val);
2292 case XPATH_BOOLEAN:
2293 res = xmlXPathCastBooleanToString(val->boolval);
2294 break;
2295 case XPATH_NUMBER:
2296 res = xmlXPathCastNumberToString(val->floatval);
2297 break;
2298 case XPATH_USERS:
2299 case XPATH_POINT:
2300 case XPATH_RANGE:
2301 case XPATH_LOCATIONSET:
2302 TODO;
2303 break;
2304 }
2305 xmlXPathReleaseObject(ctxt, val);
2306 if (res == NULL)
2307 return(xmlXPathCacheNewCString(ctxt, ""));
2308 return(xmlXPathCacheWrapString(ctxt, res));
2309}
2310
2311/**
2312 * xmlXPathCacheObjectCopy:
2313 * @ctxt: the XPath context
2314 * @val: the original object
2315 *
2316 * This is the cached version of xmlXPathObjectCopy().
2317 * Acquire a copy of a given object
2318 *
2319 * Returns a created or reused created object.
2320 */
2321static xmlXPathObjectPtr
2322xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2323{
2324 if (val == NULL)
2325 return(NULL);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002326
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002327 if (XP_HAS_CACHE(ctxt)) {
2328 switch (val->type) {
2329 case XPATH_NODESET:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002330 return(xmlXPathCacheWrapNodeSet(ctxt,
2331 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002332 case XPATH_STRING:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002333 return(xmlXPathCacheNewString(ctxt, val->stringval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002334 case XPATH_BOOLEAN:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002335 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002336 case XPATH_NUMBER:
2337 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2338 default:
2339 break;
2340 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002341 }
2342 return(xmlXPathObjectCopy(val));
2343}
2344
2345/**
2346 * xmlXPathCacheConvertBoolean:
2347 * @ctxt: the XPath context
2348 * @val: an XPath object
2349 *
2350 * This is the cached version of xmlXPathConvertBoolean().
2351 * Converts an existing object to its boolean() equivalent
2352 *
2353 * Returns a created or reused object, the old one is freed (or the operation
2354 * is done directly on @val)
2355 */
2356static xmlXPathObjectPtr
2357xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2358 xmlXPathObjectPtr ret;
2359
2360 if (val == NULL)
2361 return(xmlXPathCacheNewBoolean(ctxt, 0));
2362 if (val->type == XPATH_BOOLEAN)
2363 return(val);
2364 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2365 xmlXPathReleaseObject(ctxt, val);
2366 return(ret);
2367}
2368
2369/**
2370 * xmlXPathCacheConvertNumber:
2371 * @ctxt: the XPath context
2372 * @val: an XPath object
2373 *
2374 * This is the cached version of xmlXPathConvertNumber().
2375 * Converts an existing object to its number() equivalent
2376 *
2377 * Returns a created or reused object, the old one is freed (or the operation
2378 * is done directly on @val)
2379 */
2380static xmlXPathObjectPtr
2381xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2382 xmlXPathObjectPtr ret;
2383
2384 if (val == NULL)
2385 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2386 if (val->type == XPATH_NUMBER)
2387 return(val);
2388 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2389 xmlXPathReleaseObject(ctxt, val);
2390 return(ret);
2391}
2392
2393/************************************************************************
2394 * *
Owen Taylor3473f882001-02-23 17:55:21 +00002395 * Parser stacks related functions and macros *
2396 * *
2397 ************************************************************************/
2398
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002399/**
2400 * valuePop:
2401 * @ctxt: an XPath evaluation context
2402 *
2403 * Pops the top XPath object from the value stack
2404 *
2405 * Returns the XPath object just removed
2406 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002407xmlXPathObjectPtr
Daniel Veillard1c732d22002-11-30 11:22:59 +00002408valuePop(xmlXPathParserContextPtr ctxt)
2409{
2410 xmlXPathObjectPtr ret;
2411
Daniel Veillarda82b1822004-11-08 16:24:57 +00002412 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
Daniel Veillard24505b02005-07-28 23:49:35 +00002413 return (NULL);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002414 ctxt->valueNr--;
2415 if (ctxt->valueNr > 0)
2416 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2417 else
2418 ctxt->value = NULL;
2419 ret = ctxt->valueTab[ctxt->valueNr];
Daniel Veillard24505b02005-07-28 23:49:35 +00002420 ctxt->valueTab[ctxt->valueNr] = NULL;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002421 return (ret);
2422}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002423/**
2424 * valuePush:
2425 * @ctxt: an XPath evaluation context
2426 * @value: the XPath object
2427 *
2428 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002429 *
2430 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002431 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002432int
Daniel Veillard1c732d22002-11-30 11:22:59 +00002433valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2434{
Daniel Veillarda82b1822004-11-08 16:24:57 +00002435 if ((ctxt == NULL) || (value == NULL)) return(-1);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002436 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002437 xmlXPathObjectPtr *tmp;
2438
2439 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2440 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00002441 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002442 if (tmp == NULL) {
Daniel Veillard1c732d22002-11-30 11:22:59 +00002443 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
2444 return (0);
2445 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002446 ctxt->valueMax *= 2;
2447 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002448 }
2449 ctxt->valueTab[ctxt->valueNr] = value;
2450 ctxt->value = value;
2451 return (ctxt->valueNr++);
2452}
Owen Taylor3473f882001-02-23 17:55:21 +00002453
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002454/**
2455 * xmlXPathPopBoolean:
2456 * @ctxt: an XPath parser context
2457 *
2458 * Pops a boolean from the stack, handling conversion if needed.
2459 * Check error with #xmlXPathCheckError.
2460 *
2461 * Returns the boolean
2462 */
2463int
2464xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2465 xmlXPathObjectPtr obj;
2466 int ret;
2467
2468 obj = valuePop(ctxt);
2469 if (obj == NULL) {
2470 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2471 return(0);
2472 }
William M. Brack08171912003-12-29 02:52:11 +00002473 if (obj->type != XPATH_BOOLEAN)
2474 ret = xmlXPathCastToBoolean(obj);
2475 else
2476 ret = obj->boolval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002477 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002478 return(ret);
2479}
2480
2481/**
2482 * xmlXPathPopNumber:
2483 * @ctxt: an XPath parser context
2484 *
2485 * Pops a number from the stack, handling conversion if needed.
2486 * Check error with #xmlXPathCheckError.
2487 *
2488 * Returns the number
2489 */
2490double
2491xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2492 xmlXPathObjectPtr obj;
2493 double ret;
2494
2495 obj = valuePop(ctxt);
2496 if (obj == NULL) {
2497 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2498 return(0);
2499 }
William M. Brack08171912003-12-29 02:52:11 +00002500 if (obj->type != XPATH_NUMBER)
2501 ret = xmlXPathCastToNumber(obj);
2502 else
2503 ret = obj->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002504 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002505 return(ret);
2506}
2507
2508/**
2509 * xmlXPathPopString:
2510 * @ctxt: an XPath parser context
2511 *
2512 * Pops a string from the stack, handling conversion if needed.
2513 * Check error with #xmlXPathCheckError.
2514 *
2515 * Returns the string
2516 */
2517xmlChar *
2518xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2519 xmlXPathObjectPtr obj;
2520 xmlChar * ret;
2521
2522 obj = valuePop(ctxt);
2523 if (obj == NULL) {
2524 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2525 return(NULL);
2526 }
William M. Brack08171912003-12-29 02:52:11 +00002527 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002528 /* TODO: needs refactoring somewhere else */
2529 if (obj->stringval == ret)
2530 obj->stringval = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002531 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002532 return(ret);
2533}
2534
2535/**
2536 * xmlXPathPopNodeSet:
2537 * @ctxt: an XPath parser context
2538 *
2539 * Pops a node-set from the stack, handling conversion if needed.
2540 * Check error with #xmlXPathCheckError.
2541 *
2542 * Returns the node-set
2543 */
2544xmlNodeSetPtr
2545xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2546 xmlXPathObjectPtr obj;
2547 xmlNodeSetPtr ret;
2548
Daniel Veillardf2a36f92004-11-08 17:55:01 +00002549 if (ctxt == NULL) return(NULL);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002550 if (ctxt->value == NULL) {
2551 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2552 return(NULL);
2553 }
2554 if (!xmlXPathStackIsNodeSet(ctxt)) {
2555 xmlXPathSetTypeError(ctxt);
2556 return(NULL);
2557 }
2558 obj = valuePop(ctxt);
2559 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00002560#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00002561 /* to fix memory leak of not clearing obj->user */
2562 if (obj->boolval && obj->user != NULL)
2563 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00002564#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002565 obj->nodesetval = NULL;
2566 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002567 return(ret);
2568}
2569
2570/**
2571 * xmlXPathPopExternal:
2572 * @ctxt: an XPath parser context
2573 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002574 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002575 * Check error with #xmlXPathCheckError.
2576 *
2577 * Returns the object
2578 */
2579void *
2580xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2581 xmlXPathObjectPtr obj;
2582 void * ret;
2583
Daniel Veillarda82b1822004-11-08 16:24:57 +00002584 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002585 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2586 return(NULL);
2587 }
2588 if (ctxt->value->type != XPATH_USERS) {
2589 xmlXPathSetTypeError(ctxt);
2590 return(NULL);
2591 }
2592 obj = valuePop(ctxt);
2593 ret = obj->user;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002594 obj->user = NULL;
2595 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002596 return(ret);
2597}
2598
Owen Taylor3473f882001-02-23 17:55:21 +00002599/*
2600 * Macros for accessing the content. Those should be used only by the parser,
2601 * and not exported.
2602 *
2603 * Dirty macros, i.e. one need to make assumption on the context to use them
2604 *
2605 * CUR_PTR return the current pointer to the xmlChar to be parsed.
2606 * CUR returns the current xmlChar value, i.e. a 8 bit value
2607 * in ISO-Latin or UTF-8.
2608 * This should be used internally by the parser
2609 * only to compare to ASCII values otherwise it would break when
2610 * running with UTF-8 encoding.
2611 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
2612 * to compare on ASCII based substring.
2613 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2614 * strings within the parser.
2615 * CURRENT Returns the current char value, with the full decoding of
2616 * UTF-8 if we are using this mode. It returns an int.
2617 * NEXT Skip to the next character, this does the proper decoding
2618 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
2619 * It returns the pointer to the current xmlChar.
2620 */
2621
2622#define CUR (*ctxt->cur)
2623#define SKIP(val) ctxt->cur += (val)
2624#define NXT(val) ctxt->cur[(val)]
2625#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00002626#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2627
2628#define COPY_BUF(l,b,i,v) \
2629 if (l == 1) b[i++] = (xmlChar) v; \
2630 else i += xmlCopyChar(l,&b[i],v)
2631
2632#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00002633
2634#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00002635 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00002636
2637#define CURRENT (*ctxt->cur)
2638#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
2639
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002640
2641#ifndef DBL_DIG
2642#define DBL_DIG 16
2643#endif
2644#ifndef DBL_EPSILON
2645#define DBL_EPSILON 1E-9
2646#endif
2647
2648#define UPPER_DOUBLE 1E9
2649#define LOWER_DOUBLE 1E-5
2650
2651#define INTEGER_DIGITS DBL_DIG
2652#define FRACTION_DIGITS (DBL_DIG + 1)
2653#define EXPONENT_DIGITS (3 + 2)
2654
2655/**
2656 * xmlXPathFormatNumber:
2657 * @number: number to format
2658 * @buffer: output buffer
2659 * @buffersize: size of output buffer
2660 *
2661 * Convert the number into a string representation.
2662 */
2663static void
2664xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2665{
Daniel Veillardcda96922001-08-21 10:56:31 +00002666 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002667 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00002668 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002669 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002670 break;
2671 case -1:
2672 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002673 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002674 break;
2675 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00002676 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002677 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002678 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00002679 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002680 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002681 } else if (number == ((int) number)) {
2682 char work[30];
2683 char *ptr, *cur;
Daniel Veillardb3d14912005-09-04 20:47:39 +00002684 int value = (int) number;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002685
2686 ptr = &buffer[0];
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002687 if (value == 0) {
2688 *ptr++ = '0';
2689 } else {
Daniel Veillardb3d14912005-09-04 20:47:39 +00002690 snprintf(work, 29, "%d", value);
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002691 cur = &work[0];
Daniel Veillardb3d14912005-09-04 20:47:39 +00002692 while ((*cur) && (ptr - buffer < buffersize)) {
2693 *ptr++ = *cur++;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002694 }
2695 }
2696 if (ptr - buffer < buffersize) {
2697 *ptr = 0;
2698 } else if (buffersize > 0) {
2699 ptr--;
2700 *ptr = 0;
2701 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002702 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002703 /* 3 is sign, decimal point, and terminating zero */
2704 char work[DBL_DIG + EXPONENT_DIGITS + 3];
2705 int integer_place, fraction_place;
2706 char *ptr;
2707 char *after_fraction;
2708 double absolute_value;
2709 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002710
Bjorn Reese70a9da52001-04-21 16:57:29 +00002711 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002712
Bjorn Reese70a9da52001-04-21 16:57:29 +00002713 /*
2714 * First choose format - scientific or regular floating point.
2715 * In either case, result is in work, and after_fraction points
2716 * just past the fractional part.
2717 */
2718 if ( ((absolute_value > UPPER_DOUBLE) ||
2719 (absolute_value < LOWER_DOUBLE)) &&
2720 (absolute_value != 0.0) ) {
2721 /* Use scientific notation */
2722 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2723 fraction_place = DBL_DIG - 1;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002724 size = snprintf(work, sizeof(work),"%*.*e",
Bjorn Reese70a9da52001-04-21 16:57:29 +00002725 integer_place, fraction_place, number);
Daniel Veillard11ce4002006-03-10 00:36:23 +00002726 while ((size > 0) && (work[size] != 'e')) size--;
2727 after_fraction = work + size;
2728
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002729 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002730 else {
2731 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00002732 if (absolute_value > 0.0)
2733 integer_place = 1 + (int)log10(absolute_value);
2734 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00002735 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002736 fraction_place = (integer_place > 0)
2737 ? DBL_DIG - integer_place
2738 : DBL_DIG;
2739 size = snprintf(work, sizeof(work), "%0.*f",
2740 fraction_place, number);
2741 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002742 }
2743
Bjorn Reese70a9da52001-04-21 16:57:29 +00002744 /* Remove fractional trailing zeroes */
2745 ptr = after_fraction;
2746 while (*(--ptr) == '0')
2747 ;
2748 if (*ptr != '.')
2749 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002750 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002751
2752 /* Finally copy result back to caller */
2753 size = strlen(work) + 1;
2754 if (size > buffersize) {
2755 work[buffersize - 1] = 0;
2756 size = buffersize;
2757 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002758 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002759 }
2760 break;
2761 }
2762}
2763
Owen Taylor3473f882001-02-23 17:55:21 +00002764
2765/************************************************************************
2766 * *
2767 * Routines to handle NodeSets *
2768 * *
2769 ************************************************************************/
2770
2771/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002772 * xmlXPathOrderDocElems:
2773 * @doc: an input document
2774 *
2775 * Call this routine to speed up XPath computation on static documents.
2776 * This stamps all the element nodes with the document order
2777 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00002778 * field, the value stored is actually - the node number (starting at -1)
2779 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002780 *
William M. Brack08171912003-12-29 02:52:11 +00002781 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002782 * of error.
2783 */
2784long
2785xmlXPathOrderDocElems(xmlDocPtr doc) {
2786 long count = 0;
2787 xmlNodePtr cur;
2788
2789 if (doc == NULL)
2790 return(-1);
2791 cur = doc->children;
2792 while (cur != NULL) {
2793 if (cur->type == XML_ELEMENT_NODE) {
2794 cur->content = (void *) (-(++count));
2795 if (cur->children != NULL) {
2796 cur = cur->children;
2797 continue;
2798 }
2799 }
2800 if (cur->next != NULL) {
2801 cur = cur->next;
2802 continue;
2803 }
2804 do {
2805 cur = cur->parent;
2806 if (cur == NULL)
2807 break;
2808 if (cur == (xmlNodePtr) doc) {
2809 cur = NULL;
2810 break;
2811 }
2812 if (cur->next != NULL) {
2813 cur = cur->next;
2814 break;
2815 }
2816 } while (cur != NULL);
2817 }
2818 return(count);
2819}
2820
2821/**
Owen Taylor3473f882001-02-23 17:55:21 +00002822 * xmlXPathCmpNodes:
2823 * @node1: the first node
2824 * @node2: the second node
2825 *
2826 * Compare two nodes w.r.t document order
2827 *
2828 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00002829 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00002830 */
2831int
2832xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2833 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002834 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002835 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002836 xmlNodePtr cur, root;
2837
2838 if ((node1 == NULL) || (node2 == NULL))
2839 return(-2);
2840 /*
2841 * a couple of optimizations which will avoid computations in most cases
2842 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00002843 if (node1->type == XML_ATTRIBUTE_NODE) {
2844 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002845 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002846 node1 = node1->parent;
2847 }
2848 if (node2->type == XML_ATTRIBUTE_NODE) {
2849 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002850 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002851 node2 = node2->parent;
2852 }
2853 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00002854 if (attr1 == attr2) {
2855 /* not required, but we keep attributes in order */
2856 if (attr1 != 0) {
2857 cur = attrNode2->prev;
2858 while (cur != NULL) {
2859 if (cur == attrNode1)
2860 return (1);
2861 cur = cur->prev;
2862 }
2863 return (-1);
2864 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00002865 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00002866 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00002867 if (attr2 == 1)
2868 return(1);
2869 return(-1);
2870 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002871 if ((node1->type == XML_NAMESPACE_DECL) ||
2872 (node2->type == XML_NAMESPACE_DECL))
2873 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00002874 if (node1 == node2->prev)
2875 return(1);
2876 if (node1 == node2->next)
2877 return(-1);
2878
2879 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002880 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002881 */
2882 if ((node1->type == XML_ELEMENT_NODE) &&
2883 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002884 (0 > (long) node1->content) &&
2885 (0 > (long) node2->content) &&
2886 (node1->doc == node2->doc)) {
2887 long l1, l2;
2888
2889 l1 = -((long) node1->content);
2890 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002891 if (l1 < l2)
2892 return(1);
2893 if (l1 > l2)
2894 return(-1);
2895 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002896
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002897 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002898 * compute depth to root
2899 */
2900 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2901 if (cur == node1)
2902 return(1);
2903 depth2++;
2904 }
2905 root = cur;
2906 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2907 if (cur == node2)
2908 return(-1);
2909 depth1++;
2910 }
2911 /*
2912 * Distinct document (or distinct entities :-( ) case.
2913 */
2914 if (root != cur) {
2915 return(-2);
2916 }
2917 /*
2918 * get the nearest common ancestor.
2919 */
2920 while (depth1 > depth2) {
2921 depth1--;
2922 node1 = node1->parent;
2923 }
2924 while (depth2 > depth1) {
2925 depth2--;
2926 node2 = node2->parent;
2927 }
2928 while (node1->parent != node2->parent) {
2929 node1 = node1->parent;
2930 node2 = node2->parent;
2931 /* should not happen but just in case ... */
2932 if ((node1 == NULL) || (node2 == NULL))
2933 return(-2);
2934 }
2935 /*
2936 * Find who's first.
2937 */
Daniel Veillardf49be472004-02-17 11:48:18 +00002938 if (node1 == node2->prev)
2939 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00002940 if (node1 == node2->next)
2941 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00002942 /*
2943 * Speedup using document order if availble.
2944 */
2945 if ((node1->type == XML_ELEMENT_NODE) &&
2946 (node2->type == XML_ELEMENT_NODE) &&
2947 (0 > (long) node1->content) &&
2948 (0 > (long) node2->content) &&
2949 (node1->doc == node2->doc)) {
2950 long l1, l2;
2951
2952 l1 = -((long) node1->content);
2953 l2 = -((long) node2->content);
2954 if (l1 < l2)
2955 return(1);
2956 if (l1 > l2)
2957 return(-1);
2958 }
2959
Owen Taylor3473f882001-02-23 17:55:21 +00002960 for (cur = node1->next;cur != NULL;cur = cur->next)
2961 if (cur == node2)
2962 return(1);
2963 return(-1); /* assume there is no sibling list corruption */
2964}
2965
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00002966#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002967/**
2968 * xmlXPathCmpNodesExt:
2969 * @node1: the first node
2970 * @node2: the second node
2971 *
2972 * Compare two nodes w.r.t document order.
2973 * This one is optimized for handling of non-element nodes.
2974 *
2975 * Returns -2 in case of error 1 if first point < second point, 0 if
2976 * it's the same node, -1 otherwise
2977 */
2978static int
2979xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
2980 int depth1, depth2;
2981 int misc = 0, precedence1 = 0, precedence2 = 0;
2982 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
2983 xmlNodePtr cur, root;
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00002984 long l1, l2;
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002985
2986 if ((node1 == NULL) || (node2 == NULL))
2987 return(-2);
2988
2989 if (node1 == node2)
2990 return(0);
2991
2992 /*
2993 * a couple of optimizations which will avoid computations in most cases
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00002994 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002995 switch (node1->type) {
2996 case XML_ELEMENT_NODE:
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00002997 if (node2->type == XML_ELEMENT_NODE) {
2998 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
2999 (0 > (long) node2->content) &&
3000 (node1->doc == node2->doc))
3001 {
3002 l1 = -((long) node1->content);
3003 l2 = -((long) node2->content);
3004 if (l1 < l2)
3005 return(1);
3006 if (l1 > l2)
3007 return(-1);
3008 } else
3009 goto turtle_comparison;
3010 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003011 break;
3012 case XML_ATTRIBUTE_NODE:
3013 precedence1 = 1; /* element is owner */
3014 miscNode1 = node1;
3015 node1 = node1->parent;
3016 misc = 1;
3017 break;
3018 case XML_TEXT_NODE:
3019 case XML_CDATA_SECTION_NODE:
3020 case XML_COMMENT_NODE:
3021 case XML_PI_NODE: {
3022 miscNode1 = node1;
3023 /*
3024 * Find nearest element node.
3025 */
3026 if (node1->prev != NULL) {
3027 do {
3028 node1 = node1->prev;
3029 if (node1->type == XML_ELEMENT_NODE) {
3030 precedence1 = 3; /* element in prev-sibl axis */
3031 break;
3032 }
3033 if (node1->prev == NULL) {
3034 precedence1 = 2; /* element is parent */
3035 /*
3036 * URGENT TODO: Are there any cases, where the
3037 * parent of such a node is not an element node?
3038 */
3039 node1 = node1->parent;
3040 break;
3041 }
3042 } while (1);
3043 } else {
3044 precedence1 = 2; /* element is parent */
3045 node1 = node1->parent;
3046 }
3047 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE)) {
3048 /*
3049 * Fallback for whatever case.
3050 */
3051 node1 = miscNode1;
3052 precedence1 = 0;
3053 } else
3054 misc = 1;
3055 }
3056 break;
3057 case XML_NAMESPACE_DECL:
3058 /*
3059 * TODO: why do we return 1 for namespace nodes?
3060 */
3061 return(1);
3062 default:
3063 break;
3064 }
3065 switch (node2->type) {
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003066 case XML_ELEMENT_NODE:
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003067 break;
3068 case XML_ATTRIBUTE_NODE:
3069 precedence2 = 1; /* element is owner */
3070 miscNode2 = node2;
3071 node2 = node2->parent;
3072 misc = 1;
3073 break;
3074 case XML_TEXT_NODE:
3075 case XML_CDATA_SECTION_NODE:
3076 case XML_COMMENT_NODE:
3077 case XML_PI_NODE: {
3078 miscNode2 = node2;
3079 if (node2->prev != NULL) {
3080 do {
3081 node2 = node2->prev;
3082 if (node2->type == XML_ELEMENT_NODE) {
3083 precedence2 = 3; /* element in prev-sibl axis */
3084 break;
3085 }
3086 if (node2->prev == NULL) {
3087 precedence2 = 2; /* element is parent */
3088 node2 = node2->parent;
3089 break;
3090 }
3091 } while (1);
3092 } else {
3093 precedence2 = 2; /* element is parent */
3094 node2 = node2->parent;
3095 }
3096 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3097 (0 <= (long) node1->content))
3098 {
3099 node2 = miscNode2;
3100 precedence2 = 0;
3101 } else
3102 misc = 1;
3103 }
3104 break;
3105 case XML_NAMESPACE_DECL:
3106 return(1);
3107 default:
3108 break;
3109 }
3110 if (misc) {
3111 if (node1 == node2) {
3112 if (precedence1 == precedence2) {
3113 /*
3114 * The ugly case; but normally there aren't many
3115 * adjacent non-element nodes around.
3116 */
3117 cur = miscNode2->prev;
3118 while (cur != NULL) {
3119 if (cur == miscNode1)
3120 return(1);
3121 if (cur->type == XML_ELEMENT_NODE)
3122 return(-1);
3123 cur = cur->prev;
3124 }
3125 return (-1);
3126 } else {
3127 /*
3128 * Evaluate based on higher precedence wrt to the element.
3129 * TODO: This assumes attributes are sorted before content.
3130 * Is this 100% correct?
3131 */
3132 if (precedence1 < precedence2)
3133 return(1);
3134 else
3135 return(-1);
3136 }
3137 }
3138 /*
3139 * Special case: One of the helper-elements is contained by the other.
3140 * <foo>
3141 * <node2>
3142 * <node1>Text-1(precedence1 == 2)</node1>
3143 * </node2>
3144 * Text-6(precedence2 == 3)
3145 * </foo>
3146 */
3147 if ((precedence2 == 3) && (precedence1 > 1)) {
3148 cur = node1->parent;
3149 while (cur) {
3150 if (cur == node2)
3151 return(1);
3152 cur = cur->parent;
3153 }
3154 }
3155 if ((precedence1 == 3) && (precedence2 > 1)) {
3156 cur = node2->parent;
3157 while (cur) {
3158 if (cur == node1)
3159 return(-1);
3160 cur = cur->parent;
3161 }
3162 }
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003163 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003164
3165 /*
3166 * Speedup using document order if availble.
3167 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003168 if ((node1->type == XML_ELEMENT_NODE) &&
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003169 (node2->type == XML_ELEMENT_NODE) &&
3170 (0 > (long) node1->content) &&
3171 (0 > (long) node2->content) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003172 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003173
3174 l1 = -((long) node1->content);
3175 l2 = -((long) node2->content);
3176 if (l1 < l2)
3177 return(1);
3178 if (l1 > l2)
3179 return(-1);
3180 }
3181
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003182turtle_comparison:
3183
3184 if (node1 == node2->prev)
3185 return(1);
3186 if (node1 == node2->next)
3187 return(-1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003188 /*
3189 * compute depth to root
3190 */
3191 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3192 if (cur == node1)
3193 return(1);
3194 depth2++;
3195 }
3196 root = cur;
3197 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3198 if (cur == node2)
3199 return(-1);
3200 depth1++;
3201 }
3202 /*
3203 * Distinct document (or distinct entities :-( ) case.
3204 */
3205 if (root != cur) {
3206 return(-2);
3207 }
3208 /*
3209 * get the nearest common ancestor.
3210 */
3211 while (depth1 > depth2) {
3212 depth1--;
3213 node1 = node1->parent;
3214 }
3215 while (depth2 > depth1) {
3216 depth2--;
3217 node2 = node2->parent;
3218 }
3219 while (node1->parent != node2->parent) {
3220 node1 = node1->parent;
3221 node2 = node2->parent;
3222 /* should not happen but just in case ... */
3223 if ((node1 == NULL) || (node2 == NULL))
3224 return(-2);
3225 }
3226 /*
3227 * Find who's first.
3228 */
3229 if (node1 == node2->prev)
3230 return(1);
3231 if (node1 == node2->next)
3232 return(-1);
3233 /*
3234 * Speedup using document order if availble.
3235 */
3236 if ((node1->type == XML_ELEMENT_NODE) &&
3237 (node2->type == XML_ELEMENT_NODE) &&
3238 (0 > (long) node1->content) &&
3239 (0 > (long) node2->content) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003240 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003241
3242 l1 = -((long) node1->content);
3243 l2 = -((long) node2->content);
3244 if (l1 < l2)
3245 return(1);
3246 if (l1 > l2)
3247 return(-1);
3248 }
3249
3250 for (cur = node1->next;cur != NULL;cur = cur->next)
3251 if (cur == node2)
3252 return(1);
3253 return(-1); /* assume there is no sibling list corruption */
3254}
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003255#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003256
Owen Taylor3473f882001-02-23 17:55:21 +00003257/**
3258 * xmlXPathNodeSetSort:
3259 * @set: the node set
3260 *
3261 * Sort the node set in document order
3262 */
3263void
3264xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003265 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003266 xmlNodePtr tmp;
3267
3268 if (set == NULL)
3269 return;
3270
3271 /* Use Shell's sort to sort the node-set */
3272 len = set->nodeNr;
3273 for (incr = len / 2; incr > 0; incr /= 2) {
3274 for (i = incr; i < len; i++) {
3275 j = i - incr;
3276 while (j >= 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003277#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003278 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3279 set->nodeTab[j + incr]) == -1)
3280#else
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003281 if (xmlXPathCmpNodes(set->nodeTab[j],
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003282 set->nodeTab[j + incr]) == -1)
3283#endif
3284 {
Owen Taylor3473f882001-02-23 17:55:21 +00003285 tmp = set->nodeTab[j];
3286 set->nodeTab[j] = set->nodeTab[j + incr];
3287 set->nodeTab[j + incr] = tmp;
3288 j -= incr;
3289 } else
3290 break;
3291 }
3292 }
3293 }
3294}
3295
3296#define XML_NODESET_DEFAULT 10
3297/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003298 * xmlXPathNodeSetDupNs:
3299 * @node: the parent node of the namespace XPath node
3300 * @ns: the libxml namespace declaration node.
3301 *
3302 * Namespace node in libxml don't match the XPath semantic. In a node set
3303 * the namespace nodes are duplicated and the next pointer is set to the
3304 * parent node in the XPath semantic.
3305 *
3306 * Returns the newly created object.
3307 */
3308static xmlNodePtr
3309xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3310 xmlNsPtr cur;
3311
3312 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3313 return(NULL);
3314 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3315 return((xmlNodePtr) ns);
3316
3317 /*
3318 * Allocate a new Namespace and fill the fields.
3319 */
3320 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3321 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003322 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003323 return(NULL);
3324 }
3325 memset(cur, 0, sizeof(xmlNs));
3326 cur->type = XML_NAMESPACE_DECL;
3327 if (ns->href != NULL)
3328 cur->href = xmlStrdup(ns->href);
3329 if (ns->prefix != NULL)
3330 cur->prefix = xmlStrdup(ns->prefix);
3331 cur->next = (xmlNsPtr) node;
3332 return((xmlNodePtr) cur);
3333}
3334
3335/**
3336 * xmlXPathNodeSetFreeNs:
3337 * @ns: the XPath namespace node found in a nodeset.
3338 *
William M. Brack08171912003-12-29 02:52:11 +00003339 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003340 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00003341 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003342 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00003343void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003344xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3345 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3346 return;
3347
3348 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3349 if (ns->href != NULL)
3350 xmlFree((xmlChar *)ns->href);
3351 if (ns->prefix != NULL)
3352 xmlFree((xmlChar *)ns->prefix);
3353 xmlFree(ns);
3354 }
3355}
3356
3357/**
Owen Taylor3473f882001-02-23 17:55:21 +00003358 * xmlXPathNodeSetCreate:
3359 * @val: an initial xmlNodePtr, or NULL
3360 *
3361 * Create a new xmlNodeSetPtr of type double and of value @val
3362 *
3363 * Returns the newly created object.
3364 */
3365xmlNodeSetPtr
3366xmlXPathNodeSetCreate(xmlNodePtr val) {
3367 xmlNodeSetPtr ret;
3368
3369 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3370 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003371 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003372 return(NULL);
3373 }
3374 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3375 if (val != NULL) {
3376 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3377 sizeof(xmlNodePtr));
3378 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003379 xmlXPathErrMemory(NULL, "creating nodeset\n");
3380 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003381 return(NULL);
3382 }
3383 memset(ret->nodeTab, 0 ,
3384 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3385 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003386 if (val->type == XML_NAMESPACE_DECL) {
3387 xmlNsPtr ns = (xmlNsPtr) val;
3388
3389 ret->nodeTab[ret->nodeNr++] =
3390 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3391 } else
3392 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003393 }
3394 return(ret);
3395}
3396
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003397/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003398 * xmlXPathNodeSetCreateSize:
3399 * @size: the initial size of the set
3400 *
3401 * Create a new xmlNodeSetPtr of type double and of value @val
3402 *
3403 * Returns the newly created object.
3404 */
3405static xmlNodeSetPtr
3406xmlXPathNodeSetCreateSize(int size) {
3407 xmlNodeSetPtr ret;
3408
3409 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3410 if (ret == NULL) {
3411 xmlXPathErrMemory(NULL, "creating nodeset\n");
3412 return(NULL);
3413 }
3414 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3415 if (size < XML_NODESET_DEFAULT)
3416 size = XML_NODESET_DEFAULT;
3417 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3418 if (ret->nodeTab == NULL) {
3419 xmlXPathErrMemory(NULL, "creating nodeset\n");
3420 xmlFree(ret);
3421 return(NULL);
3422 }
3423 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3424 ret->nodeMax = size;
3425 return(ret);
3426}
3427
3428/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003429 * xmlXPathNodeSetContains:
3430 * @cur: the node-set
3431 * @val: the node
3432 *
3433 * checks whether @cur contains @val
3434 *
3435 * Returns true (1) if @cur contains @val, false (0) otherwise
3436 */
3437int
3438xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3439 int i;
3440
Daniel Veillarda82b1822004-11-08 16:24:57 +00003441 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003442 if (val->type == XML_NAMESPACE_DECL) {
3443 for (i = 0; i < cur->nodeNr; i++) {
3444 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3445 xmlNsPtr ns1, ns2;
3446
3447 ns1 = (xmlNsPtr) val;
3448 ns2 = (xmlNsPtr) cur->nodeTab[i];
3449 if (ns1 == ns2)
3450 return(1);
3451 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3452 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3453 return(1);
3454 }
3455 }
3456 } else {
3457 for (i = 0; i < cur->nodeNr; i++) {
3458 if (cur->nodeTab[i] == val)
3459 return(1);
3460 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003461 }
3462 return(0);
3463}
3464
3465/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003466 * xmlXPathNodeSetAddNs:
3467 * @cur: the initial node set
3468 * @node: the hosting node
3469 * @ns: a the namespace node
3470 *
3471 * add a new namespace node to an existing NodeSet
3472 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00003473void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003474xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3475 int i;
3476
Daniel Veillarda82b1822004-11-08 16:24:57 +00003477
3478 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3479 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003480 (node->type != XML_ELEMENT_NODE))
3481 return;
3482
William M. Brack08171912003-12-29 02:52:11 +00003483 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003484 /*
William M. Brack08171912003-12-29 02:52:11 +00003485 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003486 */
3487 for (i = 0;i < cur->nodeNr;i++) {
3488 if ((cur->nodeTab[i] != NULL) &&
3489 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00003490 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003491 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3492 return;
3493 }
3494
3495 /*
3496 * grow the nodeTab if needed
3497 */
3498 if (cur->nodeMax == 0) {
3499 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3500 sizeof(xmlNodePtr));
3501 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003502 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003503 return;
3504 }
3505 memset(cur->nodeTab, 0 ,
3506 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3507 cur->nodeMax = XML_NODESET_DEFAULT;
3508 } else if (cur->nodeNr == cur->nodeMax) {
3509 xmlNodePtr *temp;
3510
3511 cur->nodeMax *= 2;
3512 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3513 sizeof(xmlNodePtr));
3514 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003515 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003516 return;
3517 }
3518 cur->nodeTab = temp;
3519 }
3520 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3521}
3522
3523/**
Owen Taylor3473f882001-02-23 17:55:21 +00003524 * xmlXPathNodeSetAdd:
3525 * @cur: the initial node set
3526 * @val: a new xmlNodePtr
3527 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003528 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00003529 */
3530void
3531xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3532 int i;
3533
Daniel Veillarda82b1822004-11-08 16:24:57 +00003534 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003535
Daniel Veillardef0b4502003-03-24 13:57:34 +00003536#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00003537 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3538 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00003539#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00003540
William M. Brack08171912003-12-29 02:52:11 +00003541 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003542 /*
William M. Brack08171912003-12-29 02:52:11 +00003543 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00003544 */
3545 for (i = 0;i < cur->nodeNr;i++)
3546 if (cur->nodeTab[i] == val) return;
3547
3548 /*
3549 * grow the nodeTab if needed
3550 */
3551 if (cur->nodeMax == 0) {
3552 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3553 sizeof(xmlNodePtr));
3554 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003555 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003556 return;
3557 }
3558 memset(cur->nodeTab, 0 ,
3559 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3560 cur->nodeMax = XML_NODESET_DEFAULT;
3561 } else if (cur->nodeNr == cur->nodeMax) {
3562 xmlNodePtr *temp;
3563
3564 cur->nodeMax *= 2;
3565 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3566 sizeof(xmlNodePtr));
3567 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003568 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003569 return;
3570 }
3571 cur->nodeTab = temp;
3572 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003573 if (val->type == XML_NAMESPACE_DECL) {
3574 xmlNsPtr ns = (xmlNsPtr) val;
3575
3576 cur->nodeTab[cur->nodeNr++] =
3577 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3578 } else
3579 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003580}
3581
3582/**
3583 * xmlXPathNodeSetAddUnique:
3584 * @cur: the initial node set
3585 * @val: a new xmlNodePtr
3586 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003587 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00003588 * when we are sure the node is not already in the set.
3589 */
3590void
3591xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00003592 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003593
Daniel Veillardef0b4502003-03-24 13:57:34 +00003594#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00003595 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3596 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00003597#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00003598
William M. Brack08171912003-12-29 02:52:11 +00003599 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003600 /*
3601 * grow the nodeTab if needed
3602 */
3603 if (cur->nodeMax == 0) {
3604 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3605 sizeof(xmlNodePtr));
3606 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003607 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003608 return;
3609 }
3610 memset(cur->nodeTab, 0 ,
3611 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3612 cur->nodeMax = XML_NODESET_DEFAULT;
3613 } else if (cur->nodeNr == cur->nodeMax) {
3614 xmlNodePtr *temp;
3615
3616 cur->nodeMax *= 2;
3617 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3618 sizeof(xmlNodePtr));
3619 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003620 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003621 return;
3622 }
3623 cur->nodeTab = temp;
3624 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003625 if (val->type == XML_NAMESPACE_DECL) {
3626 xmlNsPtr ns = (xmlNsPtr) val;
3627
3628 cur->nodeTab[cur->nodeNr++] =
3629 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3630 } else
3631 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003632}
3633
3634/**
3635 * xmlXPathNodeSetMerge:
3636 * @val1: the first NodeSet or NULL
3637 * @val2: the second NodeSet
3638 *
3639 * Merges two nodesets, all nodes from @val2 are added to @val1
3640 * if @val1 is NULL, a new set is created and copied from @val2
3641 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003642 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003643 */
3644xmlNodeSetPtr
3645xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003646 int i, j, initNr, skip;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003647 xmlNodePtr n1, n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003648
3649 if (val2 == NULL) return(val1);
3650 if (val1 == NULL) {
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003651 val1 = xmlXPathNodeSetCreate(NULL);
3652#if 0
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003653 /*
3654 * TODO: The optimization won't work in every case, since
3655 * those nasty namespace nodes need to be added with
3656 * xmlXPathNodeSetDupNs() to the set; thus a pure
3657 * memcpy is not possible.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00003658 * If there was a flag on the nodesetval, indicating that
3659 * some temporary nodes are in, that would be helpfull.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003660 */
3661 /*
3662 * Optimization: Create an equally sized node-set
3663 * and memcpy the content.
3664 */
3665 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3666 if (val1 == NULL)
3667 return(NULL);
3668 if (val2->nodeNr != 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003669 if (val2->nodeNr == 1)
3670 *(val1->nodeTab) = *(val2->nodeTab);
3671 else {
3672 memcpy(val1->nodeTab, val2->nodeTab,
3673 val2->nodeNr * sizeof(xmlNodePtr));
3674 }
3675 val1->nodeNr = val2->nodeNr;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003676 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003677 return(val1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003678#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003679 }
3680
William M. Brack08171912003-12-29 02:52:11 +00003681 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003682 initNr = val1->nodeNr;
3683
3684 for (i = 0;i < val2->nodeNr;i++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003685 n2 = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00003686 /*
William M. Brack08171912003-12-29 02:52:11 +00003687 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003688 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003689 skip = 0;
3690 for (j = 0; j < initNr; j++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003691 n1 = val1->nodeTab[j];
3692 if (n1 == n2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003693 skip = 1;
3694 break;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003695 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3696 (n2->type == XML_NAMESPACE_DECL)) {
3697 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3698 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3699 ((xmlNsPtr) n2)->prefix)))
3700 {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003701 skip = 1;
3702 break;
3703 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003704 }
3705 }
3706 if (skip)
3707 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00003708
3709 /*
3710 * grow the nodeTab if needed
3711 */
3712 if (val1->nodeMax == 0) {
3713 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3714 sizeof(xmlNodePtr));
3715 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003716 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003717 return(NULL);
3718 }
3719 memset(val1->nodeTab, 0 ,
3720 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3721 val1->nodeMax = XML_NODESET_DEFAULT;
3722 } else if (val1->nodeNr == val1->nodeMax) {
3723 xmlNodePtr *temp;
3724
3725 val1->nodeMax *= 2;
3726 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3727 sizeof(xmlNodePtr));
3728 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003729 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003730 return(NULL);
3731 }
3732 val1->nodeTab = temp;
3733 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003734 if (n2->type == XML_NAMESPACE_DECL) {
3735 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003736
3737 val1->nodeTab[val1->nodeNr++] =
3738 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3739 } else
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003740 val1->nodeTab[val1->nodeNr++] = n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003741 }
3742
3743 return(val1);
3744}
3745
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003746#if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
Owen Taylor3473f882001-02-23 17:55:21 +00003747/**
Daniel Veillard75be0132002-03-13 10:03:35 +00003748 * xmlXPathNodeSetMergeUnique:
3749 * @val1: the first NodeSet or NULL
3750 * @val2: the second NodeSet
3751 *
3752 * Merges two nodesets, all nodes from @val2 are added to @val1
3753 * if @val1 is NULL, a new set is created and copied from @val2
3754 *
3755 * Returns @val1 once extended or NULL in case of error.
3756 */
3757static xmlNodeSetPtr
3758xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00003759 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00003760
3761 if (val2 == NULL) return(val1);
3762 if (val1 == NULL) {
3763 val1 = xmlXPathNodeSetCreate(NULL);
3764 }
3765
William M. Brack08171912003-12-29 02:52:11 +00003766 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00003767
3768 for (i = 0;i < val2->nodeNr;i++) {
3769 /*
3770 * grow the nodeTab if needed
3771 */
3772 if (val1->nodeMax == 0) {
3773 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3774 sizeof(xmlNodePtr));
3775 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003776 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00003777 return(NULL);
3778 }
3779 memset(val1->nodeTab, 0 ,
3780 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3781 val1->nodeMax = XML_NODESET_DEFAULT;
3782 } else if (val1->nodeNr == val1->nodeMax) {
3783 xmlNodePtr *temp;
3784
3785 val1->nodeMax *= 2;
3786 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3787 sizeof(xmlNodePtr));
3788 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003789 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00003790 return(NULL);
3791 }
3792 val1->nodeTab = temp;
3793 }
3794 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3795 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
3796
3797 val1->nodeTab[val1->nodeNr++] =
3798 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3799 } else
3800 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
3801 }
3802
3803 return(val1);
3804}
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003805#endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3806
3807/**
3808 * xmlXPathNodeSetMergeAndClear:
3809 * @set1: the first NodeSet or NULL
3810 * @set2: the second NodeSet
3811 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3812 *
3813 * Merges two nodesets, all nodes from @set2 are added to @set1
3814 * if @set1 is NULL, a new set is created and copied from @set2.
3815 * Checks for duplicate nodes. Clears set2.
3816 *
3817 * Returns @set1 once extended or NULL in case of error.
3818 */
3819static xmlNodeSetPtr
3820xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3821 int hasNullEntries)
3822{
3823 if ((set1 == NULL) && (hasNullEntries == 0)) {
3824 /*
3825 * Note that doing a memcpy of the list, namespace nodes are
3826 * just assigned to set1, since set2 is cleared anyway.
3827 */
3828 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3829 if (set1 == NULL)
3830 return(NULL);
3831 if (set2->nodeNr != 0) {
3832 memcpy(set1->nodeTab, set2->nodeTab,
3833 set2->nodeNr * sizeof(xmlNodePtr));
3834 set1->nodeNr = set2->nodeNr;
3835 }
3836 } else {
3837 int i, j, initNbSet1;
3838 xmlNodePtr n1, n2;
3839
3840 if (set1 == NULL)
3841 set1 = xmlXPathNodeSetCreate(NULL);
3842
3843 initNbSet1 = set1->nodeNr;
3844 for (i = 0;i < set2->nodeNr;i++) {
3845 n2 = set2->nodeTab[i];
3846 /*
3847 * Skip NULLed entries.
3848 */
3849 if (n2 == NULL)
3850 continue;
3851 /*
3852 * Skip duplicates.
3853 */
3854 for (j = 0; j < initNbSet1; j++) {
3855 n1 = set1->nodeTab[j];
3856 if (n1 == n2) {
3857 goto skip_node;
3858 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3859 (n2->type == XML_NAMESPACE_DECL))
3860 {
3861 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3862 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3863 ((xmlNsPtr) n2)->prefix)))
3864 {
3865 /*
3866 * Free the namespace node.
3867 */
3868 set2->nodeTab[i] = NULL;
3869 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3870 goto skip_node;
3871 }
3872 }
3873 }
3874 /*
3875 * grow the nodeTab if needed
3876 */
3877 if (set1->nodeMax == 0) {
3878 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3879 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3880 if (set1->nodeTab == NULL) {
3881 xmlXPathErrMemory(NULL, "merging nodeset\n");
3882 return(NULL);
3883 }
3884 memset(set1->nodeTab, 0,
3885 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3886 set1->nodeMax = XML_NODESET_DEFAULT;
3887 } else if (set1->nodeNr >= set1->nodeMax) {
3888 xmlNodePtr *temp;
3889
3890 set1->nodeMax *= 2;
3891 temp = (xmlNodePtr *) xmlRealloc(
3892 set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3893 if (temp == NULL) {
3894 xmlXPathErrMemory(NULL, "merging nodeset\n");
3895 return(NULL);
3896 }
3897 set1->nodeTab = temp;
3898 }
3899 if (n2->type == XML_NAMESPACE_DECL) {
3900 xmlNsPtr ns = (xmlNsPtr) n2;
3901
3902 set1->nodeTab[set1->nodeNr++] =
3903 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3904 } else
3905 set1->nodeTab[set1->nodeNr++] = n2;
3906skip_node:
3907 {}
3908 }
3909 }
3910 set2->nodeNr = 0;
3911 return(set1);
3912}
3913
3914/**
3915 * xmlXPathNodeSetMergeAndClearNoDupls:
3916 * @set1: the first NodeSet or NULL
3917 * @set2: the second NodeSet
3918 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3919 *
3920 * Merges two nodesets, all nodes from @set2 are added to @set1
3921 * if @set1 is NULL, a new set is created and copied from @set2.
3922 * Doesn't chack for duplicate nodes. Clears set2.
3923 *
3924 * Returns @set1 once extended or NULL in case of error.
3925 */
3926static xmlNodeSetPtr
3927xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3928 int hasNullEntries)
3929{
3930 if (set2 == NULL)
3931 return(set1);
3932 if ((set1 == NULL) && (hasNullEntries == 0)) {
3933 /*
3934 * Note that doing a memcpy of the list, namespace nodes are
3935 * just assigned to set1, since set2 is cleared anyway.
3936 */
3937 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3938 if (set1 == NULL)
3939 return(NULL);
3940 if (set2->nodeNr != 0) {
3941 memcpy(set1->nodeTab, set2->nodeTab,
3942 set2->nodeNr * sizeof(xmlNodePtr));
3943 set1->nodeNr = set2->nodeNr;
3944 }
3945 } else {
3946 int i;
3947 xmlNodePtr n2;
3948
3949 if (set1 == NULL)
3950 set1 = xmlXPathNodeSetCreate(NULL);
3951
3952 for (i = 0;i < set2->nodeNr;i++) {
3953 n2 = set2->nodeTab[i];
3954 /*
3955 * Skip NULLed entries.
3956 */
3957 if (n2 == NULL)
3958 continue;
3959 if (set1->nodeMax == 0) {
3960 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3961 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3962 if (set1->nodeTab == NULL) {
3963 xmlXPathErrMemory(NULL, "merging nodeset\n");
3964 return(NULL);
3965 }
3966 memset(set1->nodeTab, 0,
3967 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3968 set1->nodeMax = XML_NODESET_DEFAULT;
3969 } else if (set1->nodeNr >= set1->nodeMax) {
3970 xmlNodePtr *temp;
3971
3972 set1->nodeMax *= 2;
3973 temp = (xmlNodePtr *) xmlRealloc(
3974 set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3975 if (temp == NULL) {
3976 xmlXPathErrMemory(NULL, "merging nodeset\n");
3977 return(NULL);
3978 }
3979 set1->nodeTab = temp;
3980 }
3981 set1->nodeTab[set1->nodeNr++] = n2;
3982 }
3983 }
3984 set2->nodeNr = 0;
3985 return(set1);
3986}
Daniel Veillard75be0132002-03-13 10:03:35 +00003987
3988/**
Owen Taylor3473f882001-02-23 17:55:21 +00003989 * xmlXPathNodeSetDel:
3990 * @cur: the initial node set
3991 * @val: an xmlNodePtr
3992 *
3993 * Removes an xmlNodePtr from an existing NodeSet
3994 */
3995void
3996xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
3997 int i;
3998
3999 if (cur == NULL) return;
4000 if (val == NULL) return;
4001
4002 /*
William M. Brack08171912003-12-29 02:52:11 +00004003 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00004004 */
4005 for (i = 0;i < cur->nodeNr;i++)
4006 if (cur->nodeTab[i] == val) break;
4007
William M. Brack08171912003-12-29 02:52:11 +00004008 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00004009#ifdef DEBUG
4010 xmlGenericError(xmlGenericErrorContext,
4011 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4012 val->name);
4013#endif
4014 return;
4015 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004016 if ((cur->nodeTab[i] != NULL) &&
4017 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4018 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004019 cur->nodeNr--;
4020 for (;i < cur->nodeNr;i++)
4021 cur->nodeTab[i] = cur->nodeTab[i + 1];
4022 cur->nodeTab[cur->nodeNr] = NULL;
4023}
4024
4025/**
4026 * xmlXPathNodeSetRemove:
4027 * @cur: the initial node set
4028 * @val: the index to remove
4029 *
4030 * Removes an entry from an existing NodeSet list.
4031 */
4032void
4033xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4034 if (cur == NULL) return;
4035 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004036 if ((cur->nodeTab[val] != NULL) &&
4037 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4038 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00004039 cur->nodeNr--;
4040 for (;val < cur->nodeNr;val++)
4041 cur->nodeTab[val] = cur->nodeTab[val + 1];
4042 cur->nodeTab[cur->nodeNr] = NULL;
4043}
4044
4045/**
4046 * xmlXPathFreeNodeSet:
4047 * @obj: the xmlNodeSetPtr to free
4048 *
4049 * Free the NodeSet compound (not the actual nodes !).
4050 */
4051void
4052xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4053 if (obj == NULL) return;
4054 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004055 int i;
4056
William M. Brack08171912003-12-29 02:52:11 +00004057 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004058 for (i = 0;i < obj->nodeNr;i++)
4059 if ((obj->nodeTab[i] != NULL) &&
4060 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4061 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004062 xmlFree(obj->nodeTab);
4063 }
Owen Taylor3473f882001-02-23 17:55:21 +00004064 xmlFree(obj);
4065}
4066
4067/**
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004068 * xmlXPathNodeSetClear:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004069 * @set: the node set to clear
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004070 *
4071 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4072 * are feed), but does *not* free the list itself. Sets the length of the
4073 * list to 0.
4074 */
4075static void
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004076xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4077{
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004078 if ((set == NULL) || (set->nodeNr <= 0))
4079 return;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004080 else if (hasNsNodes) {
4081 int i;
4082 xmlNodePtr node;
4083
4084 for (i = 0; i < set->nodeNr; i++) {
4085 node = set->nodeTab[i];
4086 if ((node != NULL) &&
4087 (node->type == XML_NAMESPACE_DECL))
4088 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4089 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004090 }
4091 set->nodeNr = 0;
4092}
4093
4094/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004095 * xmlXPathNodeSetClearFromPos:
4096 * @set: the node set to be cleared
4097 * @pos: the start position to clear from
4098 *
4099 * Clears the list from temporary XPath objects (e.g. namespace nodes
4100 * are feed) starting with the entry at @pos, but does *not* free the list
4101 * itself. Sets the length of the list to @pos.
4102 */
4103static void
4104xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4105{
4106 if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4107 return;
4108 else if ((hasNsNodes)) {
4109 int i;
4110 xmlNodePtr node;
4111
4112 for (i = pos; i < set->nodeNr; i++) {
4113 node = set->nodeTab[i];
4114 if ((node != NULL) &&
4115 (node->type == XML_NAMESPACE_DECL))
4116 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4117 }
4118 }
4119 set->nodeNr = pos;
4120}
4121
4122/**
Owen Taylor3473f882001-02-23 17:55:21 +00004123 * xmlXPathFreeValueTree:
4124 * @obj: the xmlNodeSetPtr to free
4125 *
4126 * Free the NodeSet compound and the actual tree, this is different
4127 * from xmlXPathFreeNodeSet()
4128 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004129static void
Owen Taylor3473f882001-02-23 17:55:21 +00004130xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4131 int i;
4132
4133 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00004134
4135 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004136 for (i = 0;i < obj->nodeNr;i++) {
4137 if (obj->nodeTab[i] != NULL) {
4138 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4139 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4140 } else {
4141 xmlFreeNodeList(obj->nodeTab[i]);
4142 }
4143 }
4144 }
Owen Taylor3473f882001-02-23 17:55:21 +00004145 xmlFree(obj->nodeTab);
4146 }
Owen Taylor3473f882001-02-23 17:55:21 +00004147 xmlFree(obj);
4148}
4149
4150#if defined(DEBUG) || defined(DEBUG_STEP)
4151/**
4152 * xmlGenericErrorContextNodeSet:
4153 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00004154 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00004155 *
4156 * Quick display of a NodeSet
4157 */
4158void
4159xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4160 int i;
4161
4162 if (output == NULL) output = xmlGenericErrorContext;
4163 if (obj == NULL) {
4164 fprintf(output, "NodeSet == NULL !\n");
4165 return;
4166 }
4167 if (obj->nodeNr == 0) {
4168 fprintf(output, "NodeSet is empty\n");
4169 return;
4170 }
4171 if (obj->nodeTab == NULL) {
4172 fprintf(output, " nodeTab == NULL !\n");
4173 return;
4174 }
4175 for (i = 0; i < obj->nodeNr; i++) {
4176 if (obj->nodeTab[i] == NULL) {
4177 fprintf(output, " NULL !\n");
4178 return;
4179 }
4180 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4181 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4182 fprintf(output, " /");
4183 else if (obj->nodeTab[i]->name == NULL)
4184 fprintf(output, " noname!");
4185 else fprintf(output, " %s", obj->nodeTab[i]->name);
4186 }
4187 fprintf(output, "\n");
4188}
4189#endif
4190
4191/**
4192 * xmlXPathNewNodeSet:
4193 * @val: the NodePtr value
4194 *
4195 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4196 * it with the single Node @val
4197 *
4198 * Returns the newly created object.
4199 */
4200xmlXPathObjectPtr
4201xmlXPathNewNodeSet(xmlNodePtr val) {
4202 xmlXPathObjectPtr ret;
4203
4204 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4205 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004206 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004207 return(NULL);
4208 }
4209 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4210 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00004211 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004212 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00004213 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004214#ifdef XP_DEBUG_OBJ_USAGE
4215 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4216#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004217 return(ret);
4218}
4219
4220/**
4221 * xmlXPathNewValueTree:
4222 * @val: the NodePtr value
4223 *
4224 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4225 * it with the tree root @val
4226 *
4227 * Returns the newly created object.
4228 */
4229xmlXPathObjectPtr
4230xmlXPathNewValueTree(xmlNodePtr val) {
4231 xmlXPathObjectPtr ret;
4232
4233 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4234 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004235 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004236 return(NULL);
4237 }
4238 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4239 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00004240 ret->boolval = 1;
4241 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00004242 ret->nodesetval = xmlXPathNodeSetCreate(val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004243#ifdef XP_DEBUG_OBJ_USAGE
4244 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4245#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004246 return(ret);
4247}
4248
4249/**
4250 * xmlXPathNewNodeSetList:
4251 * @val: an existing NodeSet
4252 *
4253 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4254 * it with the Nodeset @val
4255 *
4256 * Returns the newly created object.
4257 */
4258xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004259xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4260{
Owen Taylor3473f882001-02-23 17:55:21 +00004261 xmlXPathObjectPtr ret;
4262 int i;
4263
4264 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004265 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00004266 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004267 ret = xmlXPathNewNodeSet(NULL);
4268 else {
4269 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4270 for (i = 1; i < val->nodeNr; ++i)
4271 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
4272 }
Owen Taylor3473f882001-02-23 17:55:21 +00004273
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004274 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004275}
4276
4277/**
4278 * xmlXPathWrapNodeSet:
4279 * @val: the NodePtr value
4280 *
4281 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4282 *
4283 * Returns the newly created object.
4284 */
4285xmlXPathObjectPtr
4286xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4287 xmlXPathObjectPtr ret;
4288
4289 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4290 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004291 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004292 return(NULL);
4293 }
4294 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4295 ret->type = XPATH_NODESET;
4296 ret->nodesetval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004297#ifdef XP_DEBUG_OBJ_USAGE
4298 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4299#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004300 return(ret);
4301}
4302
4303/**
4304 * xmlXPathFreeNodeSetList:
4305 * @obj: an existing NodeSetList object
4306 *
4307 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4308 * the list contrary to xmlXPathFreeObject().
4309 */
4310void
4311xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4312 if (obj == NULL) return;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004313#ifdef XP_DEBUG_OBJ_USAGE
4314 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4315#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004316 xmlFree(obj);
4317}
4318
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004319/**
4320 * xmlXPathDifference:
4321 * @nodes1: a node-set
4322 * @nodes2: a node-set
4323 *
4324 * Implements the EXSLT - Sets difference() function:
4325 * node-set set:difference (node-set, node-set)
4326 *
4327 * Returns the difference between the two node sets, or nodes1 if
4328 * nodes2 is empty
4329 */
4330xmlNodeSetPtr
4331xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4332 xmlNodeSetPtr ret;
4333 int i, l1;
4334 xmlNodePtr cur;
4335
4336 if (xmlXPathNodeSetIsEmpty(nodes2))
4337 return(nodes1);
4338
4339 ret = xmlXPathNodeSetCreate(NULL);
4340 if (xmlXPathNodeSetIsEmpty(nodes1))
4341 return(ret);
4342
4343 l1 = xmlXPathNodeSetGetLength(nodes1);
4344
4345 for (i = 0; i < l1; i++) {
4346 cur = xmlXPathNodeSetItem(nodes1, i);
4347 if (!xmlXPathNodeSetContains(nodes2, cur))
4348 xmlXPathNodeSetAddUnique(ret, cur);
4349 }
4350 return(ret);
4351}
4352
4353/**
4354 * xmlXPathIntersection:
4355 * @nodes1: a node-set
4356 * @nodes2: a node-set
4357 *
4358 * Implements the EXSLT - Sets intersection() function:
4359 * node-set set:intersection (node-set, node-set)
4360 *
4361 * Returns a node set comprising the nodes that are within both the
4362 * node sets passed as arguments
4363 */
4364xmlNodeSetPtr
4365xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4366 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4367 int i, l1;
4368 xmlNodePtr cur;
4369
4370 if (xmlXPathNodeSetIsEmpty(nodes1))
4371 return(ret);
4372 if (xmlXPathNodeSetIsEmpty(nodes2))
4373 return(ret);
4374
4375 l1 = xmlXPathNodeSetGetLength(nodes1);
4376
4377 for (i = 0; i < l1; i++) {
4378 cur = xmlXPathNodeSetItem(nodes1, i);
4379 if (xmlXPathNodeSetContains(nodes2, cur))
4380 xmlXPathNodeSetAddUnique(ret, cur);
4381 }
4382 return(ret);
4383}
4384
4385/**
4386 * xmlXPathDistinctSorted:
4387 * @nodes: a node-set, sorted by document order
4388 *
4389 * Implements the EXSLT - Sets distinct() function:
4390 * node-set set:distinct (node-set)
4391 *
4392 * Returns a subset of the nodes contained in @nodes, or @nodes if
4393 * it is empty
4394 */
4395xmlNodeSetPtr
4396xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4397 xmlNodeSetPtr ret;
4398 xmlHashTablePtr hash;
4399 int i, l;
4400 xmlChar * strval;
4401 xmlNodePtr cur;
4402
4403 if (xmlXPathNodeSetIsEmpty(nodes))
4404 return(nodes);
4405
4406 ret = xmlXPathNodeSetCreate(NULL);
4407 l = xmlXPathNodeSetGetLength(nodes);
4408 hash = xmlHashCreate (l);
4409 for (i = 0; i < l; i++) {
4410 cur = xmlXPathNodeSetItem(nodes, i);
4411 strval = xmlXPathCastNodeToString(cur);
4412 if (xmlHashLookup(hash, strval) == NULL) {
4413 xmlHashAddEntry(hash, strval, strval);
4414 xmlXPathNodeSetAddUnique(ret, cur);
4415 } else {
4416 xmlFree(strval);
4417 }
4418 }
4419 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4420 return(ret);
4421}
4422
4423/**
4424 * xmlXPathDistinct:
4425 * @nodes: a node-set
4426 *
4427 * Implements the EXSLT - Sets distinct() function:
4428 * node-set set:distinct (node-set)
4429 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4430 * is called with the sorted node-set
4431 *
4432 * Returns a subset of the nodes contained in @nodes, or @nodes if
4433 * it is empty
4434 */
4435xmlNodeSetPtr
4436xmlXPathDistinct (xmlNodeSetPtr nodes) {
4437 if (xmlXPathNodeSetIsEmpty(nodes))
4438 return(nodes);
4439
4440 xmlXPathNodeSetSort(nodes);
4441 return(xmlXPathDistinctSorted(nodes));
4442}
4443
4444/**
4445 * xmlXPathHasSameNodes:
4446 * @nodes1: a node-set
4447 * @nodes2: a node-set
4448 *
4449 * Implements the EXSLT - Sets has-same-nodes function:
4450 * boolean set:has-same-node(node-set, node-set)
4451 *
4452 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4453 * otherwise
4454 */
4455int
4456xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4457 int i, l;
4458 xmlNodePtr cur;
4459
4460 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4461 xmlXPathNodeSetIsEmpty(nodes2))
4462 return(0);
4463
4464 l = xmlXPathNodeSetGetLength(nodes1);
4465 for (i = 0; i < l; i++) {
4466 cur = xmlXPathNodeSetItem(nodes1, i);
4467 if (xmlXPathNodeSetContains(nodes2, cur))
4468 return(1);
4469 }
4470 return(0);
4471}
4472
4473/**
4474 * xmlXPathNodeLeadingSorted:
4475 * @nodes: a node-set, sorted by document order
4476 * @node: a node
4477 *
4478 * Implements the EXSLT - Sets leading() function:
4479 * node-set set:leading (node-set, node-set)
4480 *
4481 * Returns the nodes in @nodes that precede @node in document order,
4482 * @nodes if @node is NULL or an empty node-set if @nodes
4483 * doesn't contain @node
4484 */
4485xmlNodeSetPtr
4486xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4487 int i, l;
4488 xmlNodePtr cur;
4489 xmlNodeSetPtr ret;
4490
4491 if (node == NULL)
4492 return(nodes);
4493
4494 ret = xmlXPathNodeSetCreate(NULL);
4495 if (xmlXPathNodeSetIsEmpty(nodes) ||
4496 (!xmlXPathNodeSetContains(nodes, node)))
4497 return(ret);
4498
4499 l = xmlXPathNodeSetGetLength(nodes);
4500 for (i = 0; i < l; i++) {
4501 cur = xmlXPathNodeSetItem(nodes, i);
4502 if (cur == node)
4503 break;
4504 xmlXPathNodeSetAddUnique(ret, cur);
4505 }
4506 return(ret);
4507}
4508
4509/**
4510 * xmlXPathNodeLeading:
4511 * @nodes: a node-set
4512 * @node: a node
4513 *
4514 * Implements the EXSLT - Sets leading() function:
4515 * node-set set:leading (node-set, node-set)
4516 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4517 * is called.
4518 *
4519 * Returns the nodes in @nodes that precede @node in document order,
4520 * @nodes if @node is NULL or an empty node-set if @nodes
4521 * doesn't contain @node
4522 */
4523xmlNodeSetPtr
4524xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4525 xmlXPathNodeSetSort(nodes);
4526 return(xmlXPathNodeLeadingSorted(nodes, node));
4527}
4528
4529/**
4530 * xmlXPathLeadingSorted:
4531 * @nodes1: a node-set, sorted by document order
4532 * @nodes2: a node-set, sorted by document order
4533 *
4534 * Implements the EXSLT - Sets leading() function:
4535 * node-set set:leading (node-set, node-set)
4536 *
4537 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4538 * in document order, @nodes1 if @nodes2 is NULL or empty or
4539 * an empty node-set if @nodes1 doesn't contain @nodes2
4540 */
4541xmlNodeSetPtr
4542xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4543 if (xmlXPathNodeSetIsEmpty(nodes2))
4544 return(nodes1);
4545 return(xmlXPathNodeLeadingSorted(nodes1,
4546 xmlXPathNodeSetItem(nodes2, 1)));
4547}
4548
4549/**
4550 * xmlXPathLeading:
4551 * @nodes1: a node-set
4552 * @nodes2: a node-set
4553 *
4554 * Implements the EXSLT - Sets leading() function:
4555 * node-set set:leading (node-set, node-set)
4556 * @nodes1 and @nodes2 are sorted by document order, then
4557 * #exslSetsLeadingSorted is called.
4558 *
4559 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4560 * in document order, @nodes1 if @nodes2 is NULL or empty or
4561 * an empty node-set if @nodes1 doesn't contain @nodes2
4562 */
4563xmlNodeSetPtr
4564xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4565 if (xmlXPathNodeSetIsEmpty(nodes2))
4566 return(nodes1);
4567 if (xmlXPathNodeSetIsEmpty(nodes1))
4568 return(xmlXPathNodeSetCreate(NULL));
4569 xmlXPathNodeSetSort(nodes1);
4570 xmlXPathNodeSetSort(nodes2);
4571 return(xmlXPathNodeLeadingSorted(nodes1,
4572 xmlXPathNodeSetItem(nodes2, 1)));
4573}
4574
4575/**
4576 * xmlXPathNodeTrailingSorted:
4577 * @nodes: a node-set, sorted by document order
4578 * @node: a node
4579 *
4580 * Implements the EXSLT - Sets trailing() function:
4581 * node-set set:trailing (node-set, node-set)
4582 *
4583 * Returns the nodes in @nodes that follow @node in document order,
4584 * @nodes if @node is NULL or an empty node-set if @nodes
4585 * doesn't contain @node
4586 */
4587xmlNodeSetPtr
4588xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4589 int i, l;
4590 xmlNodePtr cur;
4591 xmlNodeSetPtr ret;
4592
4593 if (node == NULL)
4594 return(nodes);
4595
4596 ret = xmlXPathNodeSetCreate(NULL);
4597 if (xmlXPathNodeSetIsEmpty(nodes) ||
4598 (!xmlXPathNodeSetContains(nodes, node)))
4599 return(ret);
4600
4601 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00004602 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004603 cur = xmlXPathNodeSetItem(nodes, i);
4604 if (cur == node)
4605 break;
4606 xmlXPathNodeSetAddUnique(ret, cur);
4607 }
4608 return(ret);
4609}
4610
4611/**
4612 * xmlXPathNodeTrailing:
4613 * @nodes: a node-set
4614 * @node: a node
4615 *
4616 * Implements the EXSLT - Sets trailing() function:
4617 * node-set set:trailing (node-set, node-set)
4618 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4619 * is called.
4620 *
4621 * Returns the nodes in @nodes that follow @node in document order,
4622 * @nodes if @node is NULL or an empty node-set if @nodes
4623 * doesn't contain @node
4624 */
4625xmlNodeSetPtr
4626xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4627 xmlXPathNodeSetSort(nodes);
4628 return(xmlXPathNodeTrailingSorted(nodes, node));
4629}
4630
4631/**
4632 * xmlXPathTrailingSorted:
4633 * @nodes1: a node-set, sorted by document order
4634 * @nodes2: a node-set, sorted by document order
4635 *
4636 * Implements the EXSLT - Sets trailing() function:
4637 * node-set set:trailing (node-set, node-set)
4638 *
4639 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4640 * in document order, @nodes1 if @nodes2 is NULL or empty or
4641 * an empty node-set if @nodes1 doesn't contain @nodes2
4642 */
4643xmlNodeSetPtr
4644xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4645 if (xmlXPathNodeSetIsEmpty(nodes2))
4646 return(nodes1);
4647 return(xmlXPathNodeTrailingSorted(nodes1,
4648 xmlXPathNodeSetItem(nodes2, 0)));
4649}
4650
4651/**
4652 * xmlXPathTrailing:
4653 * @nodes1: a node-set
4654 * @nodes2: a node-set
4655 *
4656 * Implements the EXSLT - Sets trailing() function:
4657 * node-set set:trailing (node-set, node-set)
4658 * @nodes1 and @nodes2 are sorted by document order, then
4659 * #xmlXPathTrailingSorted is called.
4660 *
4661 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4662 * in document order, @nodes1 if @nodes2 is NULL or empty or
4663 * an empty node-set if @nodes1 doesn't contain @nodes2
4664 */
4665xmlNodeSetPtr
4666xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4667 if (xmlXPathNodeSetIsEmpty(nodes2))
4668 return(nodes1);
4669 if (xmlXPathNodeSetIsEmpty(nodes1))
4670 return(xmlXPathNodeSetCreate(NULL));
4671 xmlXPathNodeSetSort(nodes1);
4672 xmlXPathNodeSetSort(nodes2);
4673 return(xmlXPathNodeTrailingSorted(nodes1,
4674 xmlXPathNodeSetItem(nodes2, 0)));
4675}
4676
Owen Taylor3473f882001-02-23 17:55:21 +00004677/************************************************************************
4678 * *
4679 * Routines to handle extra functions *
4680 * *
4681 ************************************************************************/
4682
4683/**
4684 * xmlXPathRegisterFunc:
4685 * @ctxt: the XPath context
4686 * @name: the function name
4687 * @f: the function implementation or NULL
4688 *
4689 * Register a new function. If @f is NULL it unregisters the function
4690 *
4691 * Returns 0 in case of success, -1 in case of error
4692 */
4693int
4694xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4695 xmlXPathFunction f) {
4696 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4697}
4698
4699/**
4700 * xmlXPathRegisterFuncNS:
4701 * @ctxt: the XPath context
4702 * @name: the function name
4703 * @ns_uri: the function namespace URI
4704 * @f: the function implementation or NULL
4705 *
4706 * Register a new function. If @f is NULL it unregisters the function
4707 *
4708 * Returns 0 in case of success, -1 in case of error
4709 */
4710int
4711xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4712 const xmlChar *ns_uri, xmlXPathFunction f) {
4713 if (ctxt == NULL)
4714 return(-1);
4715 if (name == NULL)
4716 return(-1);
4717
4718 if (ctxt->funcHash == NULL)
4719 ctxt->funcHash = xmlHashCreate(0);
4720 if (ctxt->funcHash == NULL)
4721 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004722 if (f == NULL)
4723 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
William M. Brackad0e67c2004-12-01 14:35:10 +00004724 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
Owen Taylor3473f882001-02-23 17:55:21 +00004725}
4726
4727/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00004728 * xmlXPathRegisterFuncLookup:
4729 * @ctxt: the XPath context
4730 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004731 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00004732 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004733 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00004734 */
4735void
4736xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4737 xmlXPathFuncLookupFunc f,
4738 void *funcCtxt) {
4739 if (ctxt == NULL)
4740 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004741 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004742 ctxt->funcLookupData = funcCtxt;
4743}
4744
4745/**
Owen Taylor3473f882001-02-23 17:55:21 +00004746 * xmlXPathFunctionLookup:
4747 * @ctxt: the XPath context
4748 * @name: the function name
4749 *
4750 * Search in the Function array of the context for the given
4751 * function.
4752 *
4753 * Returns the xmlXPathFunction or NULL if not found
4754 */
4755xmlXPathFunction
4756xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00004757 if (ctxt == NULL)
4758 return (NULL);
4759
4760 if (ctxt->funcLookupFunc != NULL) {
4761 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004762 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004763
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004764 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004765 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004766 if (ret != NULL)
4767 return(ret);
4768 }
Owen Taylor3473f882001-02-23 17:55:21 +00004769 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4770}
4771
4772/**
4773 * xmlXPathFunctionLookupNS:
4774 * @ctxt: the XPath context
4775 * @name: the function name
4776 * @ns_uri: the function namespace URI
4777 *
4778 * Search in the Function array of the context for the given
4779 * function.
4780 *
4781 * Returns the xmlXPathFunction or NULL if not found
4782 */
4783xmlXPathFunction
4784xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4785 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00004786 xmlXPathFunction ret;
4787
Owen Taylor3473f882001-02-23 17:55:21 +00004788 if (ctxt == NULL)
4789 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004790 if (name == NULL)
4791 return(NULL);
4792
Thomas Broyerba4ad322001-07-26 16:55:21 +00004793 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004794 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004795
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004796 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004797 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004798 if (ret != NULL)
4799 return(ret);
4800 }
4801
4802 if (ctxt->funcHash == NULL)
4803 return(NULL);
4804
William M. Brackad0e67c2004-12-01 14:35:10 +00004805 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4806 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004807}
4808
4809/**
4810 * xmlXPathRegisteredFuncsCleanup:
4811 * @ctxt: the XPath context
4812 *
4813 * Cleanup the XPath context data associated to registered functions
4814 */
4815void
4816xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4817 if (ctxt == NULL)
4818 return;
4819
4820 xmlHashFree(ctxt->funcHash, NULL);
4821 ctxt->funcHash = NULL;
4822}
4823
4824/************************************************************************
4825 * *
William M. Brack08171912003-12-29 02:52:11 +00004826 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00004827 * *
4828 ************************************************************************/
4829
4830/**
4831 * xmlXPathRegisterVariable:
4832 * @ctxt: the XPath context
4833 * @name: the variable name
4834 * @value: the variable value or NULL
4835 *
4836 * Register a new variable value. If @value is NULL it unregisters
4837 * the variable
4838 *
4839 * Returns 0 in case of success, -1 in case of error
4840 */
4841int
4842xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4843 xmlXPathObjectPtr value) {
4844 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4845}
4846
4847/**
4848 * xmlXPathRegisterVariableNS:
4849 * @ctxt: the XPath context
4850 * @name: the variable name
4851 * @ns_uri: the variable namespace URI
4852 * @value: the variable value or NULL
4853 *
4854 * Register a new variable value. If @value is NULL it unregisters
4855 * the variable
4856 *
4857 * Returns 0 in case of success, -1 in case of error
4858 */
4859int
4860xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4861 const xmlChar *ns_uri,
4862 xmlXPathObjectPtr value) {
4863 if (ctxt == NULL)
4864 return(-1);
4865 if (name == NULL)
4866 return(-1);
4867
4868 if (ctxt->varHash == NULL)
4869 ctxt->varHash = xmlHashCreate(0);
4870 if (ctxt->varHash == NULL)
4871 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004872 if (value == NULL)
4873 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4874 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00004875 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4876 (void *) value,
4877 (xmlHashDeallocator)xmlXPathFreeObject));
4878}
4879
4880/**
4881 * xmlXPathRegisterVariableLookup:
4882 * @ctxt: the XPath context
4883 * @f: the lookup function
4884 * @data: the lookup data
4885 *
4886 * register an external mechanism to do variable lookup
4887 */
4888void
4889xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4890 xmlXPathVariableLookupFunc f, void *data) {
4891 if (ctxt == NULL)
4892 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004893 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00004894 ctxt->varLookupData = data;
4895}
4896
4897/**
4898 * xmlXPathVariableLookup:
4899 * @ctxt: the XPath context
4900 * @name: the variable name
4901 *
4902 * Search in the Variable array of the context for the given
4903 * variable value.
4904 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00004905 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00004906 */
4907xmlXPathObjectPtr
4908xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4909 if (ctxt == NULL)
4910 return(NULL);
4911
4912 if (ctxt->varLookupFunc != NULL) {
4913 xmlXPathObjectPtr ret;
4914
4915 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4916 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00004917 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004918 }
4919 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4920}
4921
4922/**
4923 * xmlXPathVariableLookupNS:
4924 * @ctxt: the XPath context
4925 * @name: the variable name
4926 * @ns_uri: the variable namespace URI
4927 *
4928 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00004929 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00004930 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00004931 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00004932 */
4933xmlXPathObjectPtr
4934xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4935 const xmlChar *ns_uri) {
4936 if (ctxt == NULL)
4937 return(NULL);
4938
4939 if (ctxt->varLookupFunc != NULL) {
4940 xmlXPathObjectPtr ret;
4941
4942 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4943 (ctxt->varLookupData, name, ns_uri);
4944 if (ret != NULL) return(ret);
4945 }
4946
4947 if (ctxt->varHash == NULL)
4948 return(NULL);
4949 if (name == NULL)
4950 return(NULL);
4951
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004952 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
Daniel Veillard8c357d52001-07-03 23:43:33 +00004953 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00004954}
4955
4956/**
4957 * xmlXPathRegisteredVariablesCleanup:
4958 * @ctxt: the XPath context
4959 *
4960 * Cleanup the XPath context data associated to registered variables
4961 */
4962void
4963xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4964 if (ctxt == NULL)
4965 return;
4966
Daniel Veillard76d66f42001-05-16 21:05:17 +00004967 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00004968 ctxt->varHash = NULL;
4969}
4970
4971/**
4972 * xmlXPathRegisterNs:
4973 * @ctxt: the XPath context
4974 * @prefix: the namespace prefix
4975 * @ns_uri: the namespace name
4976 *
4977 * Register a new namespace. If @ns_uri is NULL it unregisters
4978 * the namespace
4979 *
4980 * Returns 0 in case of success, -1 in case of error
4981 */
4982int
4983xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
4984 const xmlChar *ns_uri) {
4985 if (ctxt == NULL)
4986 return(-1);
4987 if (prefix == NULL)
4988 return(-1);
4989
4990 if (ctxt->nsHash == NULL)
4991 ctxt->nsHash = xmlHashCreate(10);
4992 if (ctxt->nsHash == NULL)
4993 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00004994 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00004995 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00004996 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00004997 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00004998 (xmlHashDeallocator)xmlFree));
4999}
5000
5001/**
5002 * xmlXPathNsLookup:
5003 * @ctxt: the XPath context
5004 * @prefix: the namespace prefix value
5005 *
5006 * Search in the namespace declaration array of the context for the given
5007 * namespace name associated to the given prefix
5008 *
5009 * Returns the value or NULL if not found
5010 */
5011const xmlChar *
5012xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5013 if (ctxt == NULL)
5014 return(NULL);
5015 if (prefix == NULL)
5016 return(NULL);
5017
5018#ifdef XML_XML_NAMESPACE
5019 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5020 return(XML_XML_NAMESPACE);
5021#endif
5022
Daniel Veillardc8f620b2001-04-30 20:31:33 +00005023 if (ctxt->namespaces != NULL) {
5024 int i;
5025
5026 for (i = 0;i < ctxt->nsNr;i++) {
5027 if ((ctxt->namespaces[i] != NULL) &&
5028 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5029 return(ctxt->namespaces[i]->href);
5030 }
5031 }
Owen Taylor3473f882001-02-23 17:55:21 +00005032
5033 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5034}
5035
5036/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005037 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00005038 * @ctxt: the XPath context
5039 *
5040 * Cleanup the XPath context data associated to registered variables
5041 */
5042void
5043xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5044 if (ctxt == NULL)
5045 return;
5046
Daniel Veillard42766c02002-08-22 20:52:17 +00005047 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00005048 ctxt->nsHash = NULL;
5049}
5050
5051/************************************************************************
5052 * *
5053 * Routines to handle Values *
5054 * *
5055 ************************************************************************/
5056
William M. Brack08171912003-12-29 02:52:11 +00005057/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005058
5059/**
5060 * xmlXPathNewFloat:
5061 * @val: the double value
5062 *
5063 * Create a new xmlXPathObjectPtr of type double and of value @val
5064 *
5065 * Returns the newly created object.
5066 */
5067xmlXPathObjectPtr
5068xmlXPathNewFloat(double val) {
5069 xmlXPathObjectPtr ret;
5070
5071 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5072 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005073 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005074 return(NULL);
5075 }
5076 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5077 ret->type = XPATH_NUMBER;
5078 ret->floatval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005079#ifdef XP_DEBUG_OBJ_USAGE
5080 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5081#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005082 return(ret);
5083}
5084
5085/**
5086 * xmlXPathNewBoolean:
5087 * @val: the boolean value
5088 *
5089 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5090 *
5091 * Returns the newly created object.
5092 */
5093xmlXPathObjectPtr
5094xmlXPathNewBoolean(int val) {
5095 xmlXPathObjectPtr ret;
5096
5097 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5098 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005099 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005100 return(NULL);
5101 }
5102 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5103 ret->type = XPATH_BOOLEAN;
5104 ret->boolval = (val != 0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005105#ifdef XP_DEBUG_OBJ_USAGE
5106 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5107#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005108 return(ret);
5109}
5110
5111/**
5112 * xmlXPathNewString:
5113 * @val: the xmlChar * value
5114 *
5115 * Create a new xmlXPathObjectPtr of type string and of value @val
5116 *
5117 * Returns the newly created object.
5118 */
5119xmlXPathObjectPtr
5120xmlXPathNewString(const xmlChar *val) {
5121 xmlXPathObjectPtr ret;
5122
5123 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5124 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005125 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005126 return(NULL);
5127 }
5128 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5129 ret->type = XPATH_STRING;
5130 if (val != NULL)
5131 ret->stringval = xmlStrdup(val);
5132 else
5133 ret->stringval = xmlStrdup((const xmlChar *)"");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005134#ifdef XP_DEBUG_OBJ_USAGE
5135 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5136#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005137 return(ret);
5138}
5139
5140/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005141 * xmlXPathWrapString:
5142 * @val: the xmlChar * value
5143 *
5144 * Wraps the @val string into an XPath object.
5145 *
5146 * Returns the newly created object.
5147 */
5148xmlXPathObjectPtr
5149xmlXPathWrapString (xmlChar *val) {
5150 xmlXPathObjectPtr ret;
5151
5152 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5153 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005154 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005155 return(NULL);
5156 }
5157 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5158 ret->type = XPATH_STRING;
5159 ret->stringval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005160#ifdef XP_DEBUG_OBJ_USAGE
5161 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5162#endif
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005163 return(ret);
5164}
5165
5166/**
Owen Taylor3473f882001-02-23 17:55:21 +00005167 * xmlXPathNewCString:
5168 * @val: the char * value
5169 *
5170 * Create a new xmlXPathObjectPtr of type string and of value @val
5171 *
5172 * Returns the newly created object.
5173 */
5174xmlXPathObjectPtr
5175xmlXPathNewCString(const char *val) {
5176 xmlXPathObjectPtr ret;
5177
5178 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5179 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005180 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005181 return(NULL);
5182 }
5183 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5184 ret->type = XPATH_STRING;
5185 ret->stringval = xmlStrdup(BAD_CAST val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005186#ifdef XP_DEBUG_OBJ_USAGE
5187 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5188#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005189 return(ret);
5190}
5191
5192/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005193 * xmlXPathWrapCString:
5194 * @val: the char * value
5195 *
5196 * Wraps a string into an XPath object.
5197 *
5198 * Returns the newly created object.
5199 */
5200xmlXPathObjectPtr
5201xmlXPathWrapCString (char * val) {
5202 return(xmlXPathWrapString((xmlChar *)(val)));
5203}
5204
5205/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005206 * xmlXPathWrapExternal:
5207 * @val: the user data
5208 *
5209 * Wraps the @val data into an XPath object.
5210 *
5211 * Returns the newly created object.
5212 */
5213xmlXPathObjectPtr
5214xmlXPathWrapExternal (void *val) {
5215 xmlXPathObjectPtr ret;
5216
5217 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5218 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005219 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005220 return(NULL);
5221 }
5222 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5223 ret->type = XPATH_USERS;
5224 ret->user = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005225#ifdef XP_DEBUG_OBJ_USAGE
5226 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5227#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005228 return(ret);
5229}
5230
5231/**
Owen Taylor3473f882001-02-23 17:55:21 +00005232 * xmlXPathObjectCopy:
5233 * @val: the original object
5234 *
5235 * allocate a new copy of a given object
5236 *
5237 * Returns the newly created object.
5238 */
5239xmlXPathObjectPtr
5240xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5241 xmlXPathObjectPtr ret;
5242
5243 if (val == NULL)
5244 return(NULL);
5245
5246 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5247 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005248 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005249 return(NULL);
5250 }
5251 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005252#ifdef XP_DEBUG_OBJ_USAGE
5253 xmlXPathDebugObjUsageRequested(NULL, val->type);
5254#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005255 switch (val->type) {
5256 case XPATH_BOOLEAN:
5257 case XPATH_NUMBER:
5258 case XPATH_POINT:
5259 case XPATH_RANGE:
5260 break;
5261 case XPATH_STRING:
5262 ret->stringval = xmlStrdup(val->stringval);
5263 break;
5264 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00005265#if 0
5266/*
5267 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5268 this previous handling is no longer correct, and can cause some serious
5269 problems (ref. bug 145547)
5270*/
Owen Taylor3473f882001-02-23 17:55:21 +00005271 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005272 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005273 xmlNodePtr cur, tmp;
5274 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005275
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005276 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005277 top = xmlNewDoc(NULL);
5278 top->name = (char *)
5279 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005280 ret->user = top;
5281 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005282 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005283 cur = val->nodesetval->nodeTab[0]->children;
5284 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005285 tmp = xmlDocCopyNode(cur, top, 1);
5286 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005287 cur = cur->next;
5288 }
5289 }
William M. Bracke9449c52004-07-11 14:41:20 +00005290
Daniel Veillard9adc0462003-03-24 18:39:54 +00005291 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005292 } else
Owen Taylor3473f882001-02-23 17:55:21 +00005293 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005294 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00005295 break;
William M. Bracke9449c52004-07-11 14:41:20 +00005296#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005297 case XPATH_NODESET:
5298 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005299 /* Do not deallocate the copied tree value */
5300 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005301 break;
5302 case XPATH_LOCATIONSET:
5303#ifdef LIBXML_XPTR_ENABLED
5304 {
5305 xmlLocationSetPtr loc = val->user;
5306 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5307 break;
5308 }
5309#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00005310 case XPATH_USERS:
5311 ret->user = val->user;
5312 break;
5313 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00005314 xmlGenericError(xmlGenericErrorContext,
5315 "xmlXPathObjectCopy: unsupported type %d\n",
5316 val->type);
5317 break;
5318 }
5319 return(ret);
5320}
5321
5322/**
5323 * xmlXPathFreeObject:
5324 * @obj: the object to free
5325 *
5326 * Free up an xmlXPathObjectPtr object.
5327 */
5328void
5329xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5330 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005331 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00005332 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00005333#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005334 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005335 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00005336 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00005337 } else
5338#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005339 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
William M. Bracke9449c52004-07-11 14:41:20 +00005340 if (obj->nodesetval != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005341 xmlXPathFreeValueTree(obj->nodesetval);
Daniel Veillard77851712001-02-27 21:54:07 +00005342 } else {
5343 if (obj->nodesetval != NULL)
5344 xmlXPathFreeNodeSet(obj->nodesetval);
5345 }
Owen Taylor3473f882001-02-23 17:55:21 +00005346#ifdef LIBXML_XPTR_ENABLED
5347 } else if (obj->type == XPATH_LOCATIONSET) {
5348 if (obj->user != NULL)
5349 xmlXPtrFreeLocationSet(obj->user);
5350#endif
5351 } else if (obj->type == XPATH_STRING) {
5352 if (obj->stringval != NULL)
5353 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005354 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005355#ifdef XP_DEBUG_OBJ_USAGE
5356 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5357#endif
5358 xmlFree(obj);
5359}
Owen Taylor3473f882001-02-23 17:55:21 +00005360
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005361/**
5362 * xmlXPathReleaseObject:
5363 * @obj: the xmlXPathObjectPtr to free or to cache
5364 *
5365 * Depending on the state of the cache this frees the given
5366 * XPath object or stores it in the cache.
5367 */
5368static void
5369xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5370{
5371#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5372 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5373 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5374
5375#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5376
5377 if (obj == NULL)
5378 return;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005379 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005380 xmlXPathFreeObject(obj);
5381 } else {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005382 xmlXPathContextCachePtr cache =
5383 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005384
5385 switch (obj->type) {
5386 case XPATH_NODESET:
5387 case XPATH_XSLT_TREE:
5388 if (obj->nodesetval != NULL) {
5389 if (obj->boolval) {
5390 /*
5391 * It looks like the @boolval is used for
5392 * evaluation if this an XSLT Result Tree Fragment.
5393 * TODO: Check if this assumption is correct.
5394 */
5395 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5396 xmlXPathFreeValueTree(obj->nodesetval);
5397 obj->nodesetval = NULL;
5398 } else if ((obj->nodesetval->nodeMax <= 40) &&
5399 (XP_CACHE_WANTS(cache->nodesetObjs,
5400 cache->maxNodeset)))
5401 {
5402 XP_CACHE_ADD(cache->nodesetObjs, obj);
5403 goto obj_cached;
5404 } else {
5405 xmlXPathFreeNodeSet(obj->nodesetval);
5406 obj->nodesetval = NULL;
5407 }
5408 }
5409 break;
5410 case XPATH_STRING:
5411 if (obj->stringval != NULL)
5412 xmlFree(obj->stringval);
5413
5414 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5415 XP_CACHE_ADD(cache->stringObjs, obj);
5416 goto obj_cached;
5417 }
5418 break;
5419 case XPATH_BOOLEAN:
5420 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5421 XP_CACHE_ADD(cache->booleanObjs, obj);
5422 goto obj_cached;
5423 }
5424 break;
5425 case XPATH_NUMBER:
5426 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5427 XP_CACHE_ADD(cache->numberObjs, obj);
5428 goto obj_cached;
5429 }
5430 break;
5431#ifdef LIBXML_XPTR_ENABLED
5432 case XPATH_LOCATIONSET:
5433 if (obj->user != NULL) {
5434 xmlXPtrFreeLocationSet(obj->user);
5435 }
5436 goto free_obj;
5437#endif
5438 default:
5439 goto free_obj;
5440 }
5441
5442 /*
5443 * Fallback to adding to the misc-objects slot.
5444 */
5445 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5446 XP_CACHE_ADD(cache->miscObjs, obj);
5447 } else
5448 goto free_obj;
5449
5450obj_cached:
5451
5452#ifdef XP_DEBUG_OBJ_USAGE
5453 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5454#endif
5455
5456 if (obj->nodesetval != NULL) {
5457 xmlNodeSetPtr tmpset = obj->nodesetval;
5458
5459 /*
5460 * TODO: Due to those nasty ns-nodes, we need to traverse
5461 * the list and free the ns-nodes.
5462 * URGENT TODO: Check if it's actually slowing things down.
5463 * Maybe we shouldn't try to preserve the list.
5464 */
5465 if (tmpset->nodeNr > 1) {
5466 int i;
5467 xmlNodePtr node;
5468
5469 for (i = 0; i < tmpset->nodeNr; i++) {
5470 node = tmpset->nodeTab[i];
5471 if ((node != NULL) &&
5472 (node->type == XML_NAMESPACE_DECL))
5473 {
5474 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5475 }
5476 }
5477 } else if (tmpset->nodeNr == 1) {
5478 if ((tmpset->nodeTab[0] != NULL) &&
5479 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5480 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5481 }
5482 tmpset->nodeNr = 0;
5483 memset(obj, 0, sizeof(xmlXPathObject));
5484 obj->nodesetval = tmpset;
5485 } else
5486 memset(obj, 0, sizeof(xmlXPathObject));
5487
5488 return;
5489
5490free_obj:
5491 /*
5492 * Cache is full; free the object.
5493 */
5494 if (obj->nodesetval != NULL)
5495 xmlXPathFreeNodeSet(obj->nodesetval);
5496#ifdef XP_DEBUG_OBJ_USAGE
5497 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5498#endif
5499 xmlFree(obj);
5500 }
5501 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005502}
5503
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005504
5505/************************************************************************
5506 * *
5507 * Type Casting Routines *
5508 * *
5509 ************************************************************************/
5510
5511/**
5512 * xmlXPathCastBooleanToString:
5513 * @val: a boolean
5514 *
5515 * Converts a boolean to its string value.
5516 *
5517 * Returns a newly allocated string.
5518 */
5519xmlChar *
5520xmlXPathCastBooleanToString (int val) {
5521 xmlChar *ret;
5522 if (val)
5523 ret = xmlStrdup((const xmlChar *) "true");
5524 else
5525 ret = xmlStrdup((const xmlChar *) "false");
5526 return(ret);
5527}
5528
5529/**
5530 * xmlXPathCastNumberToString:
5531 * @val: a number
5532 *
5533 * Converts a number to its string value.
5534 *
5535 * Returns a newly allocated string.
5536 */
5537xmlChar *
5538xmlXPathCastNumberToString (double val) {
5539 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00005540 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005541 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005542 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005543 break;
5544 case -1:
5545 ret = xmlStrdup((const xmlChar *) "-Infinity");
5546 break;
5547 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00005548 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005549 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005550 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5551 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005552 } else {
5553 /* could be improved */
5554 char buf[100];
Daniel Veillard11ce4002006-03-10 00:36:23 +00005555 xmlXPathFormatNumber(val, buf, 99);
5556 buf[99] = 0;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005557 ret = xmlStrdup((const xmlChar *) buf);
5558 }
5559 }
5560 return(ret);
5561}
5562
5563/**
5564 * xmlXPathCastNodeToString:
5565 * @node: a node
5566 *
5567 * Converts a node to its string value.
5568 *
5569 * Returns a newly allocated string.
5570 */
5571xmlChar *
5572xmlXPathCastNodeToString (xmlNodePtr node) {
5573 return(xmlNodeGetContent(node));
5574}
5575
5576/**
5577 * xmlXPathCastNodeSetToString:
5578 * @ns: a node-set
5579 *
5580 * Converts a node-set to its string value.
5581 *
5582 * Returns a newly allocated string.
5583 */
5584xmlChar *
5585xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5586 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5587 return(xmlStrdup((const xmlChar *) ""));
5588
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00005589 if (ns->nodeNr > 1)
5590 xmlXPathNodeSetSort(ns);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005591 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5592}
5593
5594/**
5595 * xmlXPathCastToString:
5596 * @val: an XPath object
5597 *
5598 * Converts an existing object to its string() equivalent
5599 *
5600 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005601 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005602 * string object).
5603 */
5604xmlChar *
5605xmlXPathCastToString(xmlXPathObjectPtr val) {
5606 xmlChar *ret = NULL;
5607
5608 if (val == NULL)
5609 return(xmlStrdup((const xmlChar *) ""));
5610 switch (val->type) {
5611 case XPATH_UNDEFINED:
5612#ifdef DEBUG_EXPR
5613 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5614#endif
5615 ret = xmlStrdup((const xmlChar *) "");
5616 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005617 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005618 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005619 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5620 break;
5621 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00005622 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005623 case XPATH_BOOLEAN:
5624 ret = xmlXPathCastBooleanToString(val->boolval);
5625 break;
5626 case XPATH_NUMBER: {
5627 ret = xmlXPathCastNumberToString(val->floatval);
5628 break;
5629 }
5630 case XPATH_USERS:
5631 case XPATH_POINT:
5632 case XPATH_RANGE:
5633 case XPATH_LOCATIONSET:
5634 TODO
5635 ret = xmlStrdup((const xmlChar *) "");
5636 break;
5637 }
5638 return(ret);
5639}
5640
5641/**
5642 * xmlXPathConvertString:
5643 * @val: an XPath object
5644 *
5645 * Converts an existing object to its string() equivalent
5646 *
5647 * Returns the new object, the old one is freed (or the operation
5648 * is done directly on @val)
5649 */
5650xmlXPathObjectPtr
5651xmlXPathConvertString(xmlXPathObjectPtr val) {
5652 xmlChar *res = NULL;
5653
5654 if (val == NULL)
5655 return(xmlXPathNewCString(""));
5656
5657 switch (val->type) {
5658 case XPATH_UNDEFINED:
5659#ifdef DEBUG_EXPR
5660 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5661#endif
5662 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005663 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005664 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005665 res = xmlXPathCastNodeSetToString(val->nodesetval);
5666 break;
5667 case XPATH_STRING:
5668 return(val);
5669 case XPATH_BOOLEAN:
5670 res = xmlXPathCastBooleanToString(val->boolval);
5671 break;
5672 case XPATH_NUMBER:
5673 res = xmlXPathCastNumberToString(val->floatval);
5674 break;
5675 case XPATH_USERS:
5676 case XPATH_POINT:
5677 case XPATH_RANGE:
5678 case XPATH_LOCATIONSET:
5679 TODO;
5680 break;
5681 }
5682 xmlXPathFreeObject(val);
5683 if (res == NULL)
5684 return(xmlXPathNewCString(""));
5685 return(xmlXPathWrapString(res));
5686}
5687
5688/**
5689 * xmlXPathCastBooleanToNumber:
5690 * @val: a boolean
5691 *
5692 * Converts a boolean to its number value
5693 *
5694 * Returns the number value
5695 */
5696double
5697xmlXPathCastBooleanToNumber(int val) {
5698 if (val)
5699 return(1.0);
5700 return(0.0);
5701}
5702
5703/**
5704 * xmlXPathCastStringToNumber:
5705 * @val: a string
5706 *
5707 * Converts a string to its number value
5708 *
5709 * Returns the number value
5710 */
5711double
5712xmlXPathCastStringToNumber(const xmlChar * val) {
5713 return(xmlXPathStringEvalNumber(val));
5714}
5715
5716/**
5717 * xmlXPathCastNodeToNumber:
5718 * @node: a node
5719 *
5720 * Converts a node to its number value
5721 *
5722 * Returns the number value
5723 */
5724double
5725xmlXPathCastNodeToNumber (xmlNodePtr node) {
5726 xmlChar *strval;
5727 double ret;
5728
5729 if (node == NULL)
5730 return(xmlXPathNAN);
5731 strval = xmlXPathCastNodeToString(node);
5732 if (strval == NULL)
5733 return(xmlXPathNAN);
5734 ret = xmlXPathCastStringToNumber(strval);
5735 xmlFree(strval);
5736
5737 return(ret);
5738}
5739
5740/**
5741 * xmlXPathCastNodeSetToNumber:
5742 * @ns: a node-set
5743 *
5744 * Converts a node-set to its number value
5745 *
5746 * Returns the number value
5747 */
5748double
5749xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5750 xmlChar *str;
5751 double ret;
5752
5753 if (ns == NULL)
5754 return(xmlXPathNAN);
5755 str = xmlXPathCastNodeSetToString(ns);
5756 ret = xmlXPathCastStringToNumber(str);
5757 xmlFree(str);
5758 return(ret);
5759}
5760
5761/**
5762 * xmlXPathCastToNumber:
5763 * @val: an XPath object
5764 *
5765 * Converts an XPath object to its number value
5766 *
5767 * Returns the number value
5768 */
5769double
5770xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5771 double ret = 0.0;
5772
5773 if (val == NULL)
5774 return(xmlXPathNAN);
5775 switch (val->type) {
5776 case XPATH_UNDEFINED:
5777#ifdef DEGUB_EXPR
5778 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5779#endif
5780 ret = xmlXPathNAN;
5781 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005782 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005783 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005784 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5785 break;
5786 case XPATH_STRING:
5787 ret = xmlXPathCastStringToNumber(val->stringval);
5788 break;
5789 case XPATH_NUMBER:
5790 ret = val->floatval;
5791 break;
5792 case XPATH_BOOLEAN:
5793 ret = xmlXPathCastBooleanToNumber(val->boolval);
5794 break;
5795 case XPATH_USERS:
5796 case XPATH_POINT:
5797 case XPATH_RANGE:
5798 case XPATH_LOCATIONSET:
5799 TODO;
5800 ret = xmlXPathNAN;
5801 break;
5802 }
5803 return(ret);
5804}
5805
5806/**
5807 * xmlXPathConvertNumber:
5808 * @val: an XPath object
5809 *
5810 * Converts an existing object to its number() equivalent
5811 *
5812 * Returns the new object, the old one is freed (or the operation
5813 * is done directly on @val)
5814 */
5815xmlXPathObjectPtr
5816xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5817 xmlXPathObjectPtr ret;
5818
5819 if (val == NULL)
5820 return(xmlXPathNewFloat(0.0));
5821 if (val->type == XPATH_NUMBER)
5822 return(val);
5823 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5824 xmlXPathFreeObject(val);
5825 return(ret);
5826}
5827
5828/**
5829 * xmlXPathCastNumberToBoolean:
5830 * @val: a number
5831 *
5832 * Converts a number to its boolean value
5833 *
5834 * Returns the boolean value
5835 */
5836int
5837xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00005838 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005839 return(0);
5840 return(1);
5841}
5842
5843/**
5844 * xmlXPathCastStringToBoolean:
5845 * @val: a string
5846 *
5847 * Converts a string to its boolean value
5848 *
5849 * Returns the boolean value
5850 */
5851int
5852xmlXPathCastStringToBoolean (const xmlChar *val) {
5853 if ((val == NULL) || (xmlStrlen(val) == 0))
5854 return(0);
5855 return(1);
5856}
5857
5858/**
5859 * xmlXPathCastNodeSetToBoolean:
5860 * @ns: a node-set
5861 *
5862 * Converts a node-set to its boolean value
5863 *
5864 * Returns the boolean value
5865 */
5866int
5867xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5868 if ((ns == NULL) || (ns->nodeNr == 0))
5869 return(0);
5870 return(1);
5871}
5872
5873/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005874 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005875 * @val: an XPath object
5876 *
5877 * Converts an XPath object to its boolean value
5878 *
5879 * Returns the boolean value
5880 */
5881int
5882xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5883 int ret = 0;
5884
5885 if (val == NULL)
5886 return(0);
5887 switch (val->type) {
5888 case XPATH_UNDEFINED:
5889#ifdef DEBUG_EXPR
5890 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
5891#endif
5892 ret = 0;
5893 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005894 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005895 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005896 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5897 break;
5898 case XPATH_STRING:
5899 ret = xmlXPathCastStringToBoolean(val->stringval);
5900 break;
5901 case XPATH_NUMBER:
5902 ret = xmlXPathCastNumberToBoolean(val->floatval);
5903 break;
5904 case XPATH_BOOLEAN:
5905 ret = val->boolval;
5906 break;
5907 case XPATH_USERS:
5908 case XPATH_POINT:
5909 case XPATH_RANGE:
5910 case XPATH_LOCATIONSET:
5911 TODO;
5912 ret = 0;
5913 break;
5914 }
5915 return(ret);
5916}
5917
5918
5919/**
5920 * xmlXPathConvertBoolean:
5921 * @val: an XPath object
5922 *
5923 * Converts an existing object to its boolean() equivalent
5924 *
5925 * Returns the new object, the old one is freed (or the operation
5926 * is done directly on @val)
5927 */
5928xmlXPathObjectPtr
5929xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
5930 xmlXPathObjectPtr ret;
5931
5932 if (val == NULL)
5933 return(xmlXPathNewBoolean(0));
5934 if (val->type == XPATH_BOOLEAN)
5935 return(val);
5936 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
5937 xmlXPathFreeObject(val);
5938 return(ret);
5939}
5940
Owen Taylor3473f882001-02-23 17:55:21 +00005941/************************************************************************
5942 * *
5943 * Routines to handle XPath contexts *
5944 * *
5945 ************************************************************************/
5946
5947/**
5948 * xmlXPathNewContext:
5949 * @doc: the XML document
5950 *
5951 * Create a new xmlXPathContext
5952 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00005953 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00005954 */
5955xmlXPathContextPtr
5956xmlXPathNewContext(xmlDocPtr doc) {
5957 xmlXPathContextPtr ret;
5958
5959 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
5960 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005961 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005962 return(NULL);
5963 }
5964 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
5965 ret->doc = doc;
5966 ret->node = NULL;
5967
5968 ret->varHash = NULL;
5969
5970 ret->nb_types = 0;
5971 ret->max_types = 0;
5972 ret->types = NULL;
5973
5974 ret->funcHash = xmlHashCreate(0);
5975
5976 ret->nb_axis = 0;
5977 ret->max_axis = 0;
5978 ret->axis = NULL;
5979
5980 ret->nsHash = NULL;
5981 ret->user = NULL;
5982
5983 ret->contextSize = -1;
5984 ret->proximityPosition = -1;
5985
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005986#ifdef XP_DEFAULT_CACHE_ON
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005987 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005988 xmlXPathFreeContext(ret);
5989 return(NULL);
5990 }
5991#endif
5992
5993 xmlXPathRegisterAllFunctions(ret);
5994
Owen Taylor3473f882001-02-23 17:55:21 +00005995 return(ret);
5996}
5997
5998/**
5999 * xmlXPathFreeContext:
6000 * @ctxt: the context to free
6001 *
6002 * Free up an xmlXPathContext
6003 */
6004void
6005xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006006 if (ctxt == NULL) return;
6007
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006008 if (ctxt->cache != NULL)
6009 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
Owen Taylor3473f882001-02-23 17:55:21 +00006010 xmlXPathRegisteredNsCleanup(ctxt);
6011 xmlXPathRegisteredFuncsCleanup(ctxt);
6012 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006013 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00006014 xmlFree(ctxt);
6015}
6016
6017/************************************************************************
6018 * *
6019 * Routines to handle XPath parser contexts *
6020 * *
6021 ************************************************************************/
6022
6023#define CHECK_CTXT(ctxt) \
6024 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00006025 __xmlRaiseError(NULL, NULL, NULL, \
6026 NULL, NULL, XML_FROM_XPATH, \
6027 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6028 __FILE__, __LINE__, \
6029 NULL, NULL, NULL, 0, 0, \
6030 "NULL context pointer\n"); \
6031 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00006032 } \
6033
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006034#define CHECK_CTXT_NEG(ctxt) \
6035 if (ctxt == NULL) { \
6036 __xmlRaiseError(NULL, NULL, NULL, \
6037 NULL, NULL, XML_FROM_XPATH, \
6038 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6039 __FILE__, __LINE__, \
6040 NULL, NULL, NULL, 0, 0, \
6041 "NULL context pointer\n"); \
6042 return(-1); \
6043 } \
6044
Owen Taylor3473f882001-02-23 17:55:21 +00006045
6046#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00006047 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
6048 (ctxt->doc->children == NULL)) { \
6049 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00006050 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00006051 }
Owen Taylor3473f882001-02-23 17:55:21 +00006052
6053
6054/**
6055 * xmlXPathNewParserContext:
6056 * @str: the XPath expression
6057 * @ctxt: the XPath context
6058 *
6059 * Create a new xmlXPathParserContext
6060 *
6061 * Returns the xmlXPathParserContext just allocated.
6062 */
6063xmlXPathParserContextPtr
6064xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6065 xmlXPathParserContextPtr ret;
6066
6067 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6068 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006069 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006070 return(NULL);
6071 }
6072 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6073 ret->cur = ret->base = str;
6074 ret->context = ctxt;
6075
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006076 ret->comp = xmlXPathNewCompExpr();
6077 if (ret->comp == NULL) {
6078 xmlFree(ret->valueTab);
6079 xmlFree(ret);
6080 return(NULL);
6081 }
Daniel Veillard4773df22004-01-23 13:15:13 +00006082 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6083 ret->comp->dict = ctxt->dict;
6084 xmlDictReference(ret->comp->dict);
6085 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006086
6087 return(ret);
6088}
6089
6090/**
6091 * xmlXPathCompParserContext:
6092 * @comp: the XPath compiled expression
6093 * @ctxt: the XPath context
6094 *
6095 * Create a new xmlXPathParserContext when processing a compiled expression
6096 *
6097 * Returns the xmlXPathParserContext just allocated.
6098 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006099static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006100xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6101 xmlXPathParserContextPtr ret;
6102
6103 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6104 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006105 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006106 return(NULL);
6107 }
6108 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6109
Owen Taylor3473f882001-02-23 17:55:21 +00006110 /* Allocate the value stack */
6111 ret->valueTab = (xmlXPathObjectPtr *)
6112 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006113 if (ret->valueTab == NULL) {
6114 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006115 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006116 return(NULL);
6117 }
Owen Taylor3473f882001-02-23 17:55:21 +00006118 ret->valueNr = 0;
6119 ret->valueMax = 10;
6120 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006121
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006122 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006123 ret->comp = comp;
6124
Owen Taylor3473f882001-02-23 17:55:21 +00006125 return(ret);
6126}
6127
6128/**
6129 * xmlXPathFreeParserContext:
6130 * @ctxt: the context to free
6131 *
6132 * Free up an xmlXPathParserContext
6133 */
6134void
6135xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6136 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006137 xmlFree(ctxt->valueTab);
6138 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00006139 if (ctxt->comp != NULL) {
6140#ifdef XPATH_STREAMING
6141 if (ctxt->comp->stream != NULL) {
6142 xmlFreePatternList(ctxt->comp->stream);
6143 ctxt->comp->stream = NULL;
6144 }
6145#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006146 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard56de87e2005-02-16 00:22:29 +00006147 }
Owen Taylor3473f882001-02-23 17:55:21 +00006148 xmlFree(ctxt);
6149}
6150
6151/************************************************************************
6152 * *
6153 * The implicit core function library *
6154 * *
6155 ************************************************************************/
6156
Owen Taylor3473f882001-02-23 17:55:21 +00006157/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006158 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00006159 * @node: a node pointer
6160 *
6161 * Function computing the beginning of the string value of the node,
6162 * used to speed up comparisons
6163 *
6164 * Returns an int usable as a hash
6165 */
6166static unsigned int
6167xmlXPathNodeValHash(xmlNodePtr node) {
6168 int len = 2;
6169 const xmlChar * string = NULL;
6170 xmlNodePtr tmp = NULL;
6171 unsigned int ret = 0;
6172
6173 if (node == NULL)
6174 return(0);
6175
Daniel Veillard9adc0462003-03-24 18:39:54 +00006176 if (node->type == XML_DOCUMENT_NODE) {
6177 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6178 if (tmp == NULL)
6179 node = node->children;
6180 else
6181 node = tmp;
6182
6183 if (node == NULL)
6184 return(0);
6185 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006186
6187 switch (node->type) {
6188 case XML_COMMENT_NODE:
6189 case XML_PI_NODE:
6190 case XML_CDATA_SECTION_NODE:
6191 case XML_TEXT_NODE:
6192 string = node->content;
6193 if (string == NULL)
6194 return(0);
6195 if (string[0] == 0)
6196 return(0);
6197 return(((unsigned int) string[0]) +
6198 (((unsigned int) string[1]) << 8));
6199 case XML_NAMESPACE_DECL:
6200 string = ((xmlNsPtr)node)->href;
6201 if (string == NULL)
6202 return(0);
6203 if (string[0] == 0)
6204 return(0);
6205 return(((unsigned int) string[0]) +
6206 (((unsigned int) string[1]) << 8));
6207 case XML_ATTRIBUTE_NODE:
6208 tmp = ((xmlAttrPtr) node)->children;
6209 break;
6210 case XML_ELEMENT_NODE:
6211 tmp = node->children;
6212 break;
6213 default:
6214 return(0);
6215 }
6216 while (tmp != NULL) {
6217 switch (tmp->type) {
6218 case XML_COMMENT_NODE:
6219 case XML_PI_NODE:
6220 case XML_CDATA_SECTION_NODE:
6221 case XML_TEXT_NODE:
6222 string = tmp->content;
6223 break;
6224 case XML_NAMESPACE_DECL:
6225 string = ((xmlNsPtr)tmp)->href;
6226 break;
6227 default:
6228 break;
6229 }
6230 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006231 if (len == 1) {
6232 return(ret + (((unsigned int) string[0]) << 8));
6233 }
6234 if (string[1] == 0) {
6235 len = 1;
6236 ret = (unsigned int) string[0];
6237 } else {
6238 return(((unsigned int) string[0]) +
6239 (((unsigned int) string[1]) << 8));
6240 }
6241 }
6242 /*
6243 * Skip to next node
6244 */
6245 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6246 if (tmp->children->type != XML_ENTITY_DECL) {
6247 tmp = tmp->children;
6248 continue;
6249 }
6250 }
6251 if (tmp == node)
6252 break;
6253
6254 if (tmp->next != NULL) {
6255 tmp = tmp->next;
6256 continue;
6257 }
6258
6259 do {
6260 tmp = tmp->parent;
6261 if (tmp == NULL)
6262 break;
6263 if (tmp == node) {
6264 tmp = NULL;
6265 break;
6266 }
6267 if (tmp->next != NULL) {
6268 tmp = tmp->next;
6269 break;
6270 }
6271 } while (tmp != NULL);
6272 }
6273 return(ret);
6274}
6275
6276/**
6277 * xmlXPathStringHash:
6278 * @string: a string
6279 *
6280 * Function computing the beginning of the string value of the node,
6281 * used to speed up comparisons
6282 *
6283 * Returns an int usable as a hash
6284 */
6285static unsigned int
6286xmlXPathStringHash(const xmlChar * string) {
6287 if (string == NULL)
6288 return((unsigned int) 0);
6289 if (string[0] == 0)
6290 return(0);
6291 return(((unsigned int) string[0]) +
6292 (((unsigned int) string[1]) << 8));
6293}
6294
6295/**
Owen Taylor3473f882001-02-23 17:55:21 +00006296 * xmlXPathCompareNodeSetFloat:
6297 * @ctxt: the XPath Parser context
6298 * @inf: less than (1) or greater than (0)
6299 * @strict: is the comparison strict
6300 * @arg: the node set
6301 * @f: the value
6302 *
6303 * Implement the compare operation between a nodeset and a number
6304 * @ns < @val (1, 1, ...
6305 * @ns <= @val (1, 0, ...
6306 * @ns > @val (0, 1, ...
6307 * @ns >= @val (0, 0, ...
6308 *
6309 * If one object to be compared is a node-set and the other is a number,
6310 * then the comparison will be true if and only if there is a node in the
6311 * node-set such that the result of performing the comparison on the number
6312 * to be compared and on the result of converting the string-value of that
6313 * node to a number using the number function is true.
6314 *
6315 * Returns 0 or 1 depending on the results of the test.
6316 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006317static int
Owen Taylor3473f882001-02-23 17:55:21 +00006318xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6319 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6320 int i, ret = 0;
6321 xmlNodeSetPtr ns;
6322 xmlChar *str2;
6323
6324 if ((f == NULL) || (arg == NULL) ||
6325 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006326 xmlXPathReleaseObject(ctxt->context, arg);
6327 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006328 return(0);
6329 }
6330 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006331 if (ns != NULL) {
6332 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006333 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006334 if (str2 != NULL) {
6335 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006336 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006337 xmlFree(str2);
6338 xmlXPathNumberFunction(ctxt, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006339 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006340 ret = xmlXPathCompareValues(ctxt, inf, strict);
6341 if (ret)
6342 break;
6343 }
6344 }
Owen Taylor3473f882001-02-23 17:55:21 +00006345 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006346 xmlXPathReleaseObject(ctxt->context, arg);
6347 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006348 return(ret);
6349}
6350
6351/**
6352 * xmlXPathCompareNodeSetString:
6353 * @ctxt: the XPath Parser context
6354 * @inf: less than (1) or greater than (0)
6355 * @strict: is the comparison strict
6356 * @arg: the node set
6357 * @s: the value
6358 *
6359 * Implement the compare operation between a nodeset and a string
6360 * @ns < @val (1, 1, ...
6361 * @ns <= @val (1, 0, ...
6362 * @ns > @val (0, 1, ...
6363 * @ns >= @val (0, 0, ...
6364 *
6365 * If one object to be compared is a node-set and the other is a string,
6366 * then the comparison will be true if and only if there is a node in
6367 * the node-set such that the result of performing the comparison on the
6368 * string-value of the node and the other string is true.
6369 *
6370 * Returns 0 or 1 depending on the results of the test.
6371 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006372static int
Owen Taylor3473f882001-02-23 17:55:21 +00006373xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6374 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6375 int i, ret = 0;
6376 xmlNodeSetPtr ns;
6377 xmlChar *str2;
6378
6379 if ((s == NULL) || (arg == NULL) ||
6380 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006381 xmlXPathReleaseObject(ctxt->context, arg);
6382 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006383 return(0);
6384 }
6385 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006386 if (ns != NULL) {
6387 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006388 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006389 if (str2 != NULL) {
6390 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006391 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006392 xmlFree(str2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006393 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006394 ret = xmlXPathCompareValues(ctxt, inf, strict);
6395 if (ret)
6396 break;
6397 }
6398 }
Owen Taylor3473f882001-02-23 17:55:21 +00006399 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006400 xmlXPathReleaseObject(ctxt->context, arg);
6401 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006402 return(ret);
6403}
6404
6405/**
6406 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006407 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00006408 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006409 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00006410 * @arg2: the second node set object
6411 *
6412 * Implement the compare operation on nodesets:
6413 *
6414 * If both objects to be compared are node-sets, then the comparison
6415 * will be true if and only if there is a node in the first node-set
6416 * and a node in the second node-set such that the result of performing
6417 * the comparison on the string-values of the two nodes is true.
6418 * ....
6419 * When neither object to be compared is a node-set and the operator
6420 * is <=, <, >= or >, then the objects are compared by converting both
6421 * objects to numbers and comparing the numbers according to IEEE 754.
6422 * ....
6423 * The number function converts its argument to a number as follows:
6424 * - a string that consists of optional whitespace followed by an
6425 * optional minus sign followed by a Number followed by whitespace
6426 * is converted to the IEEE 754 number that is nearest (according
6427 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6428 * represented by the string; any other string is converted to NaN
6429 *
6430 * Conclusion all nodes need to be converted first to their string value
6431 * and then the comparison must be done when possible
6432 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006433static int
6434xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00006435 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6436 int i, j, init = 0;
6437 double val1;
6438 double *values2;
6439 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006440 xmlNodeSetPtr ns1;
6441 xmlNodeSetPtr ns2;
6442
6443 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006444 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6445 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006446 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006447 }
Owen Taylor3473f882001-02-23 17:55:21 +00006448 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006449 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6450 xmlXPathFreeObject(arg1);
6451 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006452 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006453 }
Owen Taylor3473f882001-02-23 17:55:21 +00006454
6455 ns1 = arg1->nodesetval;
6456 ns2 = arg2->nodesetval;
6457
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006458 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006459 xmlXPathFreeObject(arg1);
6460 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006461 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006462 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006463 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006464 xmlXPathFreeObject(arg1);
6465 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006466 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006467 }
Owen Taylor3473f882001-02-23 17:55:21 +00006468
6469 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6470 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006471 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00006472 xmlXPathFreeObject(arg1);
6473 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006474 return(0);
6475 }
6476 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006477 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00006478 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00006479 continue;
6480 for (j = 0;j < ns2->nodeNr;j++) {
6481 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006482 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00006483 }
Daniel Veillardcda96922001-08-21 10:56:31 +00006484 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00006485 continue;
6486 if (inf && strict)
6487 ret = (val1 < values2[j]);
6488 else if (inf && !strict)
6489 ret = (val1 <= values2[j]);
6490 else if (!inf && strict)
6491 ret = (val1 > values2[j]);
6492 else if (!inf && !strict)
6493 ret = (val1 >= values2[j]);
6494 if (ret)
6495 break;
6496 }
6497 if (ret)
6498 break;
6499 init = 1;
6500 }
6501 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006502 xmlXPathFreeObject(arg1);
6503 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006504 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006505}
6506
6507/**
6508 * xmlXPathCompareNodeSetValue:
6509 * @ctxt: the XPath Parser context
6510 * @inf: less than (1) or greater than (0)
6511 * @strict: is the comparison strict
6512 * @arg: the node set
6513 * @val: the value
6514 *
6515 * Implement the compare operation between a nodeset and a value
6516 * @ns < @val (1, 1, ...
6517 * @ns <= @val (1, 0, ...
6518 * @ns > @val (0, 1, ...
6519 * @ns >= @val (0, 0, ...
6520 *
6521 * If one object to be compared is a node-set and the other is a boolean,
6522 * then the comparison will be true if and only if the result of performing
6523 * the comparison on the boolean and on the result of converting
6524 * the node-set to a boolean using the boolean function is true.
6525 *
6526 * Returns 0 or 1 depending on the results of the test.
6527 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006528static int
Owen Taylor3473f882001-02-23 17:55:21 +00006529xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6530 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6531 if ((val == NULL) || (arg == NULL) ||
6532 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6533 return(0);
6534
6535 switch(val->type) {
6536 case XPATH_NUMBER:
6537 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6538 case XPATH_NODESET:
6539 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006540 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00006541 case XPATH_STRING:
6542 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6543 case XPATH_BOOLEAN:
6544 valuePush(ctxt, arg);
6545 xmlXPathBooleanFunction(ctxt, 1);
6546 valuePush(ctxt, val);
6547 return(xmlXPathCompareValues(ctxt, inf, strict));
6548 default:
6549 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00006550 }
6551 return(0);
6552}
6553
6554/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006555 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00006556 * @arg: the nodeset object argument
6557 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00006558 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006559 *
6560 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6561 * If one object to be compared is a node-set and the other is a string,
6562 * then the comparison will be true if and only if there is a node in
6563 * the node-set such that the result of performing the comparison on the
6564 * string-value of the node and the other string is true.
6565 *
6566 * Returns 0 or 1 depending on the results of the test.
6567 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006568static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006569xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006570{
Owen Taylor3473f882001-02-23 17:55:21 +00006571 int i;
6572 xmlNodeSetPtr ns;
6573 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006574 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00006575
6576 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00006577 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6578 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006579 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00006580 /*
6581 * A NULL nodeset compared with a string is always false
6582 * (since there is no node equal, and no node not equal)
6583 */
6584 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00006585 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00006586 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006587 for (i = 0; i < ns->nodeNr; i++) {
6588 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6589 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6590 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6591 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006592 if (neq)
6593 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006594 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00006595 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6596 if (neq)
6597 continue;
6598 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006599 } else if (neq) {
6600 if (str2 != NULL)
6601 xmlFree(str2);
6602 return (1);
6603 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006604 if (str2 != NULL)
6605 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006606 } else if (neq)
6607 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00006608 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006609 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006610}
6611
6612/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006613 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00006614 * @arg: the nodeset object argument
6615 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00006616 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006617 *
6618 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6619 * If one object to be compared is a node-set and the other is a number,
6620 * then the comparison will be true if and only if there is a node in
6621 * the node-set such that the result of performing the comparison on the
6622 * number to be compared and on the result of converting the string-value
6623 * of that node to a number using the number function is true.
6624 *
6625 * Returns 0 or 1 depending on the results of the test.
6626 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006627static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006628xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6629 xmlXPathObjectPtr arg, double f, int neq) {
6630 int i, ret=0;
6631 xmlNodeSetPtr ns;
6632 xmlChar *str2;
6633 xmlXPathObjectPtr val;
6634 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00006635
6636 if ((arg == NULL) ||
6637 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6638 return(0);
6639
William M. Brack0c022ad2002-07-12 00:56:01 +00006640 ns = arg->nodesetval;
6641 if (ns != NULL) {
6642 for (i=0;i<ns->nodeNr;i++) {
6643 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6644 if (str2 != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006645 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
William M. Brack0c022ad2002-07-12 00:56:01 +00006646 xmlFree(str2);
6647 xmlXPathNumberFunction(ctxt, 1);
6648 val = valuePop(ctxt);
6649 v = val->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006650 xmlXPathReleaseObject(ctxt->context, val);
William M. Brack0c022ad2002-07-12 00:56:01 +00006651 if (!xmlXPathIsNaN(v)) {
6652 if ((!neq) && (v==f)) {
6653 ret = 1;
6654 break;
6655 } else if ((neq) && (v!=f)) {
6656 ret = 1;
6657 break;
6658 }
William M. Brack32f0f712005-07-14 07:00:33 +00006659 } else { /* NaN is unequal to any value */
6660 if (neq)
6661 ret = 1;
William M. Brack0c022ad2002-07-12 00:56:01 +00006662 }
6663 }
6664 }
6665 }
6666
6667 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006668}
6669
6670
6671/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006672 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00006673 * @arg1: first nodeset object argument
6674 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00006675 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006676 *
William M. Brack0c022ad2002-07-12 00:56:01 +00006677 * Implement the equal / not equal operation on XPath nodesets:
6678 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00006679 * If both objects to be compared are node-sets, then the comparison
6680 * will be true if and only if there is a node in the first node-set and
6681 * a node in the second node-set such that the result of performing the
6682 * comparison on the string-values of the two nodes is true.
6683 *
6684 * (needless to say, this is a costly operation)
6685 *
6686 * Returns 0 or 1 depending on the results of the test.
6687 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006688static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006689xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00006690 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006691 unsigned int *hashs1;
6692 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00006693 xmlChar **values1;
6694 xmlChar **values2;
6695 int ret = 0;
6696 xmlNodeSetPtr ns1;
6697 xmlNodeSetPtr ns2;
6698
6699 if ((arg1 == NULL) ||
6700 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6701 return(0);
6702 if ((arg2 == NULL) ||
6703 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6704 return(0);
6705
6706 ns1 = arg1->nodesetval;
6707 ns2 = arg2->nodesetval;
6708
Daniel Veillard911f49a2001-04-07 15:39:35 +00006709 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006710 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006711 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006712 return(0);
6713
6714 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00006715 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00006716 */
William M. Brack0c022ad2002-07-12 00:56:01 +00006717 if (neq == 0)
6718 for (i = 0;i < ns1->nodeNr;i++)
6719 for (j = 0;j < ns2->nodeNr;j++)
6720 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6721 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006722
6723 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006724 if (values1 == NULL) {
6725 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006726 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006727 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006728 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6729 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006730 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006731 xmlFree(values1);
6732 return(0);
6733 }
Owen Taylor3473f882001-02-23 17:55:21 +00006734 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6735 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6736 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006737 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006738 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00006739 xmlFree(values1);
6740 return(0);
6741 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006742 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6743 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006744 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006745 xmlFree(hashs1);
6746 xmlFree(values1);
6747 xmlFree(values2);
6748 return(0);
6749 }
Owen Taylor3473f882001-02-23 17:55:21 +00006750 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6751 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006752 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006753 for (j = 0;j < ns2->nodeNr;j++) {
6754 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006755 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006756 if (hashs1[i] != hashs2[j]) {
6757 if (neq) {
6758 ret = 1;
6759 break;
6760 }
6761 }
6762 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006763 if (values1[i] == NULL)
6764 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6765 if (values2[j] == NULL)
6766 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006767 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006768 if (ret)
6769 break;
6770 }
Owen Taylor3473f882001-02-23 17:55:21 +00006771 }
6772 if (ret)
6773 break;
6774 }
6775 for (i = 0;i < ns1->nodeNr;i++)
6776 if (values1[i] != NULL)
6777 xmlFree(values1[i]);
6778 for (j = 0;j < ns2->nodeNr;j++)
6779 if (values2[j] != NULL)
6780 xmlFree(values2[j]);
6781 xmlFree(values1);
6782 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006783 xmlFree(hashs1);
6784 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00006785 return(ret);
6786}
6787
William M. Brack0c022ad2002-07-12 00:56:01 +00006788static int
6789xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6790 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00006791 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00006792 /*
6793 *At this point we are assured neither arg1 nor arg2
6794 *is a nodeset, so we can just pick the appropriate routine.
6795 */
Owen Taylor3473f882001-02-23 17:55:21 +00006796 switch (arg1->type) {
6797 case XPATH_UNDEFINED:
6798#ifdef DEBUG_EXPR
6799 xmlGenericError(xmlGenericErrorContext,
6800 "Equal: undefined\n");
6801#endif
6802 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006803 case XPATH_BOOLEAN:
6804 switch (arg2->type) {
6805 case XPATH_UNDEFINED:
6806#ifdef DEBUG_EXPR
6807 xmlGenericError(xmlGenericErrorContext,
6808 "Equal: undefined\n");
6809#endif
6810 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006811 case XPATH_BOOLEAN:
6812#ifdef DEBUG_EXPR
6813 xmlGenericError(xmlGenericErrorContext,
6814 "Equal: %d boolean %d \n",
6815 arg1->boolval, arg2->boolval);
6816#endif
6817 ret = (arg1->boolval == arg2->boolval);
6818 break;
6819 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00006820 ret = (arg1->boolval ==
6821 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006822 break;
6823 case XPATH_STRING:
6824 if ((arg2->stringval == NULL) ||
6825 (arg2->stringval[0] == 0)) ret = 0;
6826 else
6827 ret = 1;
6828 ret = (arg1->boolval == ret);
6829 break;
6830 case XPATH_USERS:
6831 case XPATH_POINT:
6832 case XPATH_RANGE:
6833 case XPATH_LOCATIONSET:
6834 TODO
6835 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006836 case XPATH_NODESET:
6837 case XPATH_XSLT_TREE:
6838 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006839 }
6840 break;
6841 case XPATH_NUMBER:
6842 switch (arg2->type) {
6843 case XPATH_UNDEFINED:
6844#ifdef DEBUG_EXPR
6845 xmlGenericError(xmlGenericErrorContext,
6846 "Equal: undefined\n");
6847#endif
6848 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006849 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00006850 ret = (arg2->boolval==
6851 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006852 break;
6853 case XPATH_STRING:
6854 valuePush(ctxt, arg2);
6855 xmlXPathNumberFunction(ctxt, 1);
6856 arg2 = valuePop(ctxt);
6857 /* no break on purpose */
6858 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006859 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00006860 if (xmlXPathIsNaN(arg1->floatval) ||
6861 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00006862 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006863 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6864 if (xmlXPathIsInf(arg2->floatval) == 1)
6865 ret = 1;
6866 else
6867 ret = 0;
6868 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6869 if (xmlXPathIsInf(arg2->floatval) == -1)
6870 ret = 1;
6871 else
6872 ret = 0;
6873 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6874 if (xmlXPathIsInf(arg1->floatval) == 1)
6875 ret = 1;
6876 else
6877 ret = 0;
6878 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6879 if (xmlXPathIsInf(arg1->floatval) == -1)
6880 ret = 1;
6881 else
6882 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00006883 } else {
6884 ret = (arg1->floatval == arg2->floatval);
6885 }
Owen Taylor3473f882001-02-23 17:55:21 +00006886 break;
6887 case XPATH_USERS:
6888 case XPATH_POINT:
6889 case XPATH_RANGE:
6890 case XPATH_LOCATIONSET:
6891 TODO
6892 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006893 case XPATH_NODESET:
6894 case XPATH_XSLT_TREE:
6895 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006896 }
6897 break;
6898 case XPATH_STRING:
6899 switch (arg2->type) {
6900 case XPATH_UNDEFINED:
6901#ifdef DEBUG_EXPR
6902 xmlGenericError(xmlGenericErrorContext,
6903 "Equal: undefined\n");
6904#endif
6905 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006906 case XPATH_BOOLEAN:
6907 if ((arg1->stringval == NULL) ||
6908 (arg1->stringval[0] == 0)) ret = 0;
6909 else
6910 ret = 1;
6911 ret = (arg2->boolval == ret);
6912 break;
6913 case XPATH_STRING:
6914 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6915 break;
6916 case XPATH_NUMBER:
6917 valuePush(ctxt, arg1);
6918 xmlXPathNumberFunction(ctxt, 1);
6919 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006920 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00006921 if (xmlXPathIsNaN(arg1->floatval) ||
6922 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00006923 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006924 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6925 if (xmlXPathIsInf(arg2->floatval) == 1)
6926 ret = 1;
6927 else
6928 ret = 0;
6929 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6930 if (xmlXPathIsInf(arg2->floatval) == -1)
6931 ret = 1;
6932 else
6933 ret = 0;
6934 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6935 if (xmlXPathIsInf(arg1->floatval) == 1)
6936 ret = 1;
6937 else
6938 ret = 0;
6939 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6940 if (xmlXPathIsInf(arg1->floatval) == -1)
6941 ret = 1;
6942 else
6943 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00006944 } else {
6945 ret = (arg1->floatval == arg2->floatval);
6946 }
Owen Taylor3473f882001-02-23 17:55:21 +00006947 break;
6948 case XPATH_USERS:
6949 case XPATH_POINT:
6950 case XPATH_RANGE:
6951 case XPATH_LOCATIONSET:
6952 TODO
6953 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006954 case XPATH_NODESET:
6955 case XPATH_XSLT_TREE:
6956 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006957 }
6958 break;
6959 case XPATH_USERS:
6960 case XPATH_POINT:
6961 case XPATH_RANGE:
6962 case XPATH_LOCATIONSET:
6963 TODO
6964 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006965 case XPATH_NODESET:
6966 case XPATH_XSLT_TREE:
6967 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006968 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006969 xmlXPathReleaseObject(ctxt->context, arg1);
6970 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006971 return(ret);
6972}
6973
William M. Brack0c022ad2002-07-12 00:56:01 +00006974/**
6975 * xmlXPathEqualValues:
6976 * @ctxt: the XPath Parser context
6977 *
6978 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6979 *
6980 * Returns 0 or 1 depending on the results of the test.
6981 */
6982int
6983xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
6984 xmlXPathObjectPtr arg1, arg2, argtmp;
6985 int ret = 0;
6986
Daniel Veillard6128c012004-11-08 17:16:15 +00006987 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00006988 arg2 = valuePop(ctxt);
6989 arg1 = valuePop(ctxt);
6990 if ((arg1 == NULL) || (arg2 == NULL)) {
6991 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006992 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006993 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006994 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006995 XP_ERROR0(XPATH_INVALID_OPERAND);
6996 }
6997
6998 if (arg1 == arg2) {
6999#ifdef DEBUG_EXPR
7000 xmlGenericError(xmlGenericErrorContext,
7001 "Equal: by pointer\n");
7002#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00007003 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007004 return(1);
7005 }
7006
7007 /*
7008 *If either argument is a nodeset, it's a 'special case'
7009 */
7010 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7011 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7012 /*
7013 *Hack it to assure arg1 is the nodeset
7014 */
7015 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7016 argtmp = arg2;
7017 arg2 = arg1;
7018 arg1 = argtmp;
7019 }
7020 switch (arg2->type) {
7021 case XPATH_UNDEFINED:
7022#ifdef DEBUG_EXPR
7023 xmlGenericError(xmlGenericErrorContext,
7024 "Equal: undefined\n");
7025#endif
7026 break;
7027 case XPATH_NODESET:
7028 case XPATH_XSLT_TREE:
7029 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7030 break;
7031 case XPATH_BOOLEAN:
7032 if ((arg1->nodesetval == NULL) ||
7033 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7034 else
7035 ret = 1;
7036 ret = (ret == arg2->boolval);
7037 break;
7038 case XPATH_NUMBER:
7039 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7040 break;
7041 case XPATH_STRING:
7042 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7043 break;
7044 case XPATH_USERS:
7045 case XPATH_POINT:
7046 case XPATH_RANGE:
7047 case XPATH_LOCATIONSET:
7048 TODO
7049 break;
7050 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007051 xmlXPathReleaseObject(ctxt->context, arg1);
7052 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007053 return(ret);
7054 }
7055
7056 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7057}
7058
7059/**
7060 * xmlXPathNotEqualValues:
7061 * @ctxt: the XPath Parser context
7062 *
7063 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7064 *
7065 * Returns 0 or 1 depending on the results of the test.
7066 */
7067int
7068xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7069 xmlXPathObjectPtr arg1, arg2, argtmp;
7070 int ret = 0;
7071
Daniel Veillard6128c012004-11-08 17:16:15 +00007072 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00007073 arg2 = valuePop(ctxt);
7074 arg1 = valuePop(ctxt);
7075 if ((arg1 == NULL) || (arg2 == NULL)) {
7076 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007077 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007078 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007079 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007080 XP_ERROR0(XPATH_INVALID_OPERAND);
7081 }
7082
7083 if (arg1 == arg2) {
7084#ifdef DEBUG_EXPR
7085 xmlGenericError(xmlGenericErrorContext,
7086 "NotEqual: by pointer\n");
7087#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007088 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007089 return(0);
7090 }
7091
7092 /*
7093 *If either argument is a nodeset, it's a 'special case'
7094 */
7095 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7096 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7097 /*
7098 *Hack it to assure arg1 is the nodeset
7099 */
7100 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7101 argtmp = arg2;
7102 arg2 = arg1;
7103 arg1 = argtmp;
7104 }
7105 switch (arg2->type) {
7106 case XPATH_UNDEFINED:
7107#ifdef DEBUG_EXPR
7108 xmlGenericError(xmlGenericErrorContext,
7109 "NotEqual: undefined\n");
7110#endif
7111 break;
7112 case XPATH_NODESET:
7113 case XPATH_XSLT_TREE:
7114 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7115 break;
7116 case XPATH_BOOLEAN:
7117 if ((arg1->nodesetval == NULL) ||
7118 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7119 else
7120 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00007121 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00007122 break;
7123 case XPATH_NUMBER:
7124 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7125 break;
7126 case XPATH_STRING:
7127 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7128 break;
7129 case XPATH_USERS:
7130 case XPATH_POINT:
7131 case XPATH_RANGE:
7132 case XPATH_LOCATIONSET:
7133 TODO
7134 break;
7135 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007136 xmlXPathReleaseObject(ctxt->context, arg1);
7137 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007138 return(ret);
7139 }
7140
7141 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7142}
Owen Taylor3473f882001-02-23 17:55:21 +00007143
7144/**
7145 * xmlXPathCompareValues:
7146 * @ctxt: the XPath Parser context
7147 * @inf: less than (1) or greater than (0)
7148 * @strict: is the comparison strict
7149 *
7150 * Implement the compare operation on XPath objects:
7151 * @arg1 < @arg2 (1, 1, ...
7152 * @arg1 <= @arg2 (1, 0, ...
7153 * @arg1 > @arg2 (0, 1, ...
7154 * @arg1 >= @arg2 (0, 0, ...
7155 *
7156 * When neither object to be compared is a node-set and the operator is
7157 * <=, <, >=, >, then the objects are compared by converted both objects
7158 * to numbers and comparing the numbers according to IEEE 754. The <
7159 * comparison will be true if and only if the first number is less than the
7160 * second number. The <= comparison will be true if and only if the first
7161 * number is less than or equal to the second number. The > comparison
7162 * will be true if and only if the first number is greater than the second
7163 * number. The >= comparison will be true if and only if the first number
7164 * is greater than or equal to the second number.
7165 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007166 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00007167 */
7168int
7169xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007170 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007171 xmlXPathObjectPtr arg1, arg2;
7172
Daniel Veillard6128c012004-11-08 17:16:15 +00007173 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00007174 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007175 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007176 if ((arg1 == NULL) || (arg2 == NULL)) {
7177 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007178 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007179 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007180 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007181 XP_ERROR0(XPATH_INVALID_OPERAND);
7182 }
7183
William M. Brack0c022ad2002-07-12 00:56:01 +00007184 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7185 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
William M. Brackd6e347e2005-04-15 01:34:41 +00007186 /*
7187 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7188 * are not freed from within this routine; they will be freed from the
7189 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7190 */
William M. Brack0c022ad2002-07-12 00:56:01 +00007191 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7192 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007193 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007194 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00007195 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007196 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7197 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007198 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007199 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7200 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00007201 }
7202 }
7203 return(ret);
7204 }
7205
7206 if (arg1->type != XPATH_NUMBER) {
7207 valuePush(ctxt, arg1);
7208 xmlXPathNumberFunction(ctxt, 1);
7209 arg1 = valuePop(ctxt);
7210 }
7211 if (arg1->type != XPATH_NUMBER) {
7212 xmlXPathFreeObject(arg1);
7213 xmlXPathFreeObject(arg2);
7214 XP_ERROR0(XPATH_INVALID_OPERAND);
7215 }
7216 if (arg2->type != XPATH_NUMBER) {
7217 valuePush(ctxt, arg2);
7218 xmlXPathNumberFunction(ctxt, 1);
7219 arg2 = valuePop(ctxt);
7220 }
7221 if (arg2->type != XPATH_NUMBER) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007222 xmlXPathReleaseObject(ctxt->context, arg1);
7223 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007224 XP_ERROR0(XPATH_INVALID_OPERAND);
7225 }
7226 /*
7227 * Add tests for infinity and nan
7228 * => feedback on 3.4 for Inf and NaN
7229 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007230 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00007231 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007232 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007233 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007234 arg1i=xmlXPathIsInf(arg1->floatval);
7235 arg2i=xmlXPathIsInf(arg2->floatval);
7236 if (inf && strict) {
7237 if ((arg1i == -1 && arg2i != -1) ||
7238 (arg2i == 1 && arg1i != 1)) {
7239 ret = 1;
7240 } else if (arg1i == 0 && arg2i == 0) {
7241 ret = (arg1->floatval < arg2->floatval);
7242 } else {
7243 ret = 0;
7244 }
7245 }
7246 else if (inf && !strict) {
7247 if (arg1i == -1 || arg2i == 1) {
7248 ret = 1;
7249 } else if (arg1i == 0 && arg2i == 0) {
7250 ret = (arg1->floatval <= arg2->floatval);
7251 } else {
7252 ret = 0;
7253 }
7254 }
7255 else if (!inf && strict) {
7256 if ((arg1i == 1 && arg2i != 1) ||
7257 (arg2i == -1 && arg1i != -1)) {
7258 ret = 1;
7259 } else if (arg1i == 0 && arg2i == 0) {
7260 ret = (arg1->floatval > arg2->floatval);
7261 } else {
7262 ret = 0;
7263 }
7264 }
7265 else if (!inf && !strict) {
7266 if (arg1i == 1 || arg2i == -1) {
7267 ret = 1;
7268 } else if (arg1i == 0 && arg2i == 0) {
7269 ret = (arg1->floatval >= arg2->floatval);
7270 } else {
7271 ret = 0;
7272 }
7273 }
Daniel Veillard21458c82002-03-27 16:12:22 +00007274 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007275 xmlXPathReleaseObject(ctxt->context, arg1);
7276 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007277 return(ret);
7278}
7279
7280/**
7281 * xmlXPathValueFlipSign:
7282 * @ctxt: the XPath Parser context
7283 *
7284 * Implement the unary - operation on an XPath object
7285 * The numeric operators convert their operands to numbers as if
7286 * by calling the number function.
7287 */
7288void
7289xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007290 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007291 CAST_TO_NUMBER;
7292 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007293 if (xmlXPathIsNaN(ctxt->value->floatval))
7294 ctxt->value->floatval=xmlXPathNAN;
7295 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7296 ctxt->value->floatval=xmlXPathNINF;
7297 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7298 ctxt->value->floatval=xmlXPathPINF;
7299 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007300 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7301 ctxt->value->floatval = xmlXPathNZERO;
7302 else
7303 ctxt->value->floatval = 0;
7304 }
7305 else
7306 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00007307}
7308
7309/**
7310 * xmlXPathAddValues:
7311 * @ctxt: the XPath Parser context
7312 *
7313 * Implement the add operation on XPath objects:
7314 * The numeric operators convert their operands to numbers as if
7315 * by calling the number function.
7316 */
7317void
7318xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7319 xmlXPathObjectPtr arg;
7320 double val;
7321
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007322 arg = valuePop(ctxt);
7323 if (arg == NULL)
7324 XP_ERROR(XPATH_INVALID_OPERAND);
7325 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007326 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007327 CAST_TO_NUMBER;
7328 CHECK_TYPE(XPATH_NUMBER);
7329 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00007330}
7331
7332/**
7333 * xmlXPathSubValues:
7334 * @ctxt: the XPath Parser context
7335 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007336 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007337 * The numeric operators convert their operands to numbers as if
7338 * by calling the number function.
7339 */
7340void
7341xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7342 xmlXPathObjectPtr arg;
7343 double val;
7344
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007345 arg = valuePop(ctxt);
7346 if (arg == NULL)
7347 XP_ERROR(XPATH_INVALID_OPERAND);
7348 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007349 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007350 CAST_TO_NUMBER;
7351 CHECK_TYPE(XPATH_NUMBER);
7352 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007353}
7354
7355/**
7356 * xmlXPathMultValues:
7357 * @ctxt: the XPath Parser context
7358 *
7359 * Implement the multiply operation on XPath objects:
7360 * The numeric operators convert their operands to numbers as if
7361 * by calling the number function.
7362 */
7363void
7364xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7365 xmlXPathObjectPtr arg;
7366 double val;
7367
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007368 arg = valuePop(ctxt);
7369 if (arg == NULL)
7370 XP_ERROR(XPATH_INVALID_OPERAND);
7371 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007372 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007373 CAST_TO_NUMBER;
7374 CHECK_TYPE(XPATH_NUMBER);
7375 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007376}
7377
7378/**
7379 * xmlXPathDivValues:
7380 * @ctxt: the XPath Parser context
7381 *
7382 * Implement the div operation on XPath objects @arg1 / @arg2:
7383 * The numeric operators convert their operands to numbers as if
7384 * by calling the number function.
7385 */
7386void
7387xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7388 xmlXPathObjectPtr arg;
7389 double val;
7390
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007391 arg = valuePop(ctxt);
7392 if (arg == NULL)
7393 XP_ERROR(XPATH_INVALID_OPERAND);
7394 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007395 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007396 CAST_TO_NUMBER;
7397 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007398 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7399 ctxt->value->floatval = xmlXPathNAN;
7400 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007401 if (ctxt->value->floatval == 0)
7402 ctxt->value->floatval = xmlXPathNAN;
7403 else if (ctxt->value->floatval > 0)
7404 ctxt->value->floatval = xmlXPathNINF;
7405 else if (ctxt->value->floatval < 0)
7406 ctxt->value->floatval = xmlXPathPINF;
7407 }
7408 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007409 if (ctxt->value->floatval == 0)
7410 ctxt->value->floatval = xmlXPathNAN;
7411 else if (ctxt->value->floatval > 0)
7412 ctxt->value->floatval = xmlXPathPINF;
7413 else if (ctxt->value->floatval < 0)
7414 ctxt->value->floatval = xmlXPathNINF;
7415 } else
7416 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007417}
7418
7419/**
7420 * xmlXPathModValues:
7421 * @ctxt: the XPath Parser context
7422 *
7423 * Implement the mod operation on XPath objects: @arg1 / @arg2
7424 * The numeric operators convert their operands to numbers as if
7425 * by calling the number function.
7426 */
7427void
7428xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7429 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00007430 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00007431
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007432 arg = valuePop(ctxt);
7433 if (arg == NULL)
7434 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007435 arg2 = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007436 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007437 CAST_TO_NUMBER;
7438 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007439 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00007440 if (arg2 == 0)
7441 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007442 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00007443 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007444 }
Owen Taylor3473f882001-02-23 17:55:21 +00007445}
7446
7447/************************************************************************
7448 * *
7449 * The traversal functions *
7450 * *
7451 ************************************************************************/
7452
Owen Taylor3473f882001-02-23 17:55:21 +00007453/*
7454 * A traversal function enumerates nodes along an axis.
7455 * Initially it must be called with NULL, and it indicates
7456 * termination on the axis by returning NULL.
7457 */
7458typedef xmlNodePtr (*xmlXPathTraversalFunction)
7459 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7460
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007461/*
7462 * xmlXPathTraversalFunctionExt:
7463 * A traversal function enumerates nodes along an axis.
7464 * Initially it must be called with NULL, and it indicates
7465 * termination on the axis by returning NULL.
7466 * The context node of the traversal is specified via @contextNode.
7467 */
7468typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7469 (xmlNodePtr cur, xmlNodePtr contextNode);
7470
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00007471/*
7472 * xmlXPathNodeSetMergeFunction:
7473 * Used for merging node sets in xmlXPathCollectAndTest().
7474 */
7475typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7476 (xmlNodeSetPtr, xmlNodeSetPtr, int);
7477
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007478
Owen Taylor3473f882001-02-23 17:55:21 +00007479/**
7480 * xmlXPathNextSelf:
7481 * @ctxt: the XPath Parser context
7482 * @cur: the current node in the traversal
7483 *
7484 * Traversal function for the "self" direction
7485 * The self axis contains just the context node itself
7486 *
7487 * Returns the next element following that axis
7488 */
7489xmlNodePtr
7490xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007491 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007492 if (cur == NULL)
7493 return(ctxt->context->node);
7494 return(NULL);
7495}
7496
7497/**
7498 * xmlXPathNextChild:
7499 * @ctxt: the XPath Parser context
7500 * @cur: the current node in the traversal
7501 *
7502 * Traversal function for the "child" direction
7503 * The child axis contains the children of the context node in document order.
7504 *
7505 * Returns the next element following that axis
7506 */
7507xmlNodePtr
7508xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007509 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007510 if (cur == NULL) {
7511 if (ctxt->context->node == NULL) return(NULL);
7512 switch (ctxt->context->node->type) {
7513 case XML_ELEMENT_NODE:
7514 case XML_TEXT_NODE:
7515 case XML_CDATA_SECTION_NODE:
7516 case XML_ENTITY_REF_NODE:
7517 case XML_ENTITY_NODE:
7518 case XML_PI_NODE:
7519 case XML_COMMENT_NODE:
7520 case XML_NOTATION_NODE:
7521 case XML_DTD_NODE:
7522 return(ctxt->context->node->children);
7523 case XML_DOCUMENT_NODE:
7524 case XML_DOCUMENT_TYPE_NODE:
7525 case XML_DOCUMENT_FRAG_NODE:
7526 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007527#ifdef LIBXML_DOCB_ENABLED
7528 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007529#endif
7530 return(((xmlDocPtr) ctxt->context->node)->children);
7531 case XML_ELEMENT_DECL:
7532 case XML_ATTRIBUTE_DECL:
7533 case XML_ENTITY_DECL:
7534 case XML_ATTRIBUTE_NODE:
7535 case XML_NAMESPACE_DECL:
7536 case XML_XINCLUDE_START:
7537 case XML_XINCLUDE_END:
7538 return(NULL);
7539 }
7540 return(NULL);
7541 }
7542 if ((cur->type == XML_DOCUMENT_NODE) ||
7543 (cur->type == XML_HTML_DOCUMENT_NODE))
7544 return(NULL);
7545 return(cur->next);
7546}
7547
7548/**
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00007549 * xmlXPathNextChildElement:
7550 * @ctxt: the XPath Parser context
7551 * @cur: the current node in the traversal
7552 *
7553 * Traversal function for the "child" direction and nodes of type element.
7554 * The child axis contains the children of the context node in document order.
7555 *
7556 * Returns the next element following that axis
7557 */
7558static xmlNodePtr
7559xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7560 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7561 if (cur == NULL) {
7562 cur = ctxt->context->node;
7563 if (cur == NULL) return(NULL);
7564 /*
7565 * Get the first element child.
7566 */
7567 switch (cur->type) {
7568 case XML_ELEMENT_NODE:
7569 case XML_DOCUMENT_FRAG_NODE:
7570 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7571 case XML_ENTITY_NODE:
7572 cur = cur->children;
7573 if (cur != NULL) {
7574 if (cur->type == XML_ELEMENT_NODE)
7575 return(cur);
7576 do {
7577 cur = cur->next;
7578 } while ((cur != NULL) &&
7579 (cur->type != XML_ELEMENT_NODE));
7580 return(cur);
7581 }
7582 return(NULL);
7583 case XML_DOCUMENT_NODE:
7584 case XML_HTML_DOCUMENT_NODE:
7585#ifdef LIBXML_DOCB_ENABLED
7586 case XML_DOCB_DOCUMENT_NODE:
7587#endif
7588 return(xmlDocGetRootElement((xmlDocPtr) cur));
7589 default:
7590 return(NULL);
7591 }
7592 return(NULL);
7593 }
7594 /*
7595 * Get the next sibling element node.
7596 */
7597 switch (cur->type) {
7598 case XML_ELEMENT_NODE:
7599 case XML_TEXT_NODE:
7600 case XML_ENTITY_REF_NODE:
7601 case XML_ENTITY_NODE:
7602 case XML_CDATA_SECTION_NODE:
7603 case XML_PI_NODE:
7604 case XML_COMMENT_NODE:
7605 case XML_XINCLUDE_END:
7606 break;
7607 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7608 default:
7609 return(NULL);
7610 }
7611 if (cur->next != NULL) {
7612 if (cur->next->type == XML_ELEMENT_NODE)
7613 return(cur->next);
7614 cur = cur->next;
7615 do {
7616 cur = cur->next;
7617 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7618 return(cur);
7619 }
7620 return(NULL);
7621}
7622
7623/**
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007624 * xmlXPathNextDescendantOrSelfElemParent:
7625 * @ctxt: the XPath Parser context
7626 * @cur: the current node in the traversal
7627 *
7628 * Traversal function for the "descendant-or-self" axis.
7629 * Additionally it returns only nodes which can be parents of
7630 * element nodes.
7631 *
7632 *
7633 * Returns the next element following that axis
7634 */
7635static xmlNodePtr
7636xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7637 xmlNodePtr contextNode)
7638{
7639 if (cur == NULL) {
7640 if (contextNode == NULL)
7641 return(NULL);
7642 switch (contextNode->type) {
7643 case XML_ELEMENT_NODE:
7644 case XML_XINCLUDE_START:
7645 case XML_DOCUMENT_FRAG_NODE:
7646 case XML_DOCUMENT_NODE:
7647#ifdef LIBXML_DOCB_ENABLED
7648 case XML_DOCB_DOCUMENT_NODE:
7649#endif
7650 case XML_HTML_DOCUMENT_NODE:
7651 return(contextNode);
7652 default:
7653 return(NULL);
7654 }
7655 return(NULL);
7656 } else {
7657 xmlNodePtr start = cur;
7658
7659 while (cur != NULL) {
7660 switch (cur->type) {
7661 case XML_ELEMENT_NODE:
7662 /* TODO: OK to have XInclude here? */
7663 case XML_XINCLUDE_START:
7664 case XML_DOCUMENT_FRAG_NODE:
7665 if (cur != start)
7666 return(cur);
7667 if (cur->children != NULL) {
7668 cur = cur->children;
7669 continue;
7670 }
7671 break;
7672#ifdef LIBXML_DOCB_ENABLED
7673 /* Not sure if we need those here. */
7674 case XML_DOCUMENT_NODE:
7675 case XML_DOCB_DOCUMENT_NODE:
7676#endif
7677 case XML_HTML_DOCUMENT_NODE:
7678 if (cur != start)
7679 return(cur);
7680 return(xmlDocGetRootElement((xmlDocPtr) cur));
7681 default:
7682 break;
7683 }
7684
7685next_sibling:
7686 if ((cur == NULL) || (cur == contextNode))
7687 return(NULL);
7688 if (cur->next != NULL) {
7689 cur = cur->next;
7690 } else {
7691 cur = cur->parent;
7692 goto next_sibling;
7693 }
7694 }
7695 }
7696 return(NULL);
7697}
7698
7699/**
Owen Taylor3473f882001-02-23 17:55:21 +00007700 * xmlXPathNextDescendant:
7701 * @ctxt: the XPath Parser context
7702 * @cur: the current node in the traversal
7703 *
7704 * Traversal function for the "descendant" direction
7705 * the descendant axis contains the descendants of the context node in document
7706 * order; a descendant is a child or a child of a child and so on.
7707 *
7708 * Returns the next element following that axis
7709 */
7710xmlNodePtr
7711xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007712 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007713 if (cur == NULL) {
7714 if (ctxt->context->node == NULL)
7715 return(NULL);
7716 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7717 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7718 return(NULL);
7719
7720 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7721 return(ctxt->context->doc->children);
7722 return(ctxt->context->node->children);
7723 }
7724
Daniel Veillard567e1b42001-08-01 15:53:47 +00007725 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007726 /*
7727 * Do not descend on entities declarations
7728 */
7729 if (cur->children->type != XML_ENTITY_DECL) {
7730 cur = cur->children;
7731 /*
7732 * Skip DTDs
7733 */
7734 if (cur->type != XML_DTD_NODE)
7735 return(cur);
7736 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00007737 }
7738
7739 if (cur == ctxt->context->node) return(NULL);
7740
Daniel Veillard68e9e742002-11-16 15:35:11 +00007741 while (cur->next != NULL) {
7742 cur = cur->next;
7743 if ((cur->type != XML_ENTITY_DECL) &&
7744 (cur->type != XML_DTD_NODE))
7745 return(cur);
7746 }
Owen Taylor3473f882001-02-23 17:55:21 +00007747
7748 do {
7749 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00007750 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00007751 if (cur == ctxt->context->node) return(NULL);
7752 if (cur->next != NULL) {
7753 cur = cur->next;
7754 return(cur);
7755 }
7756 } while (cur != NULL);
7757 return(cur);
7758}
7759
7760/**
7761 * xmlXPathNextDescendantOrSelf:
7762 * @ctxt: the XPath Parser context
7763 * @cur: the current node in the traversal
7764 *
7765 * Traversal function for the "descendant-or-self" direction
7766 * the descendant-or-self axis contains the context node and the descendants
7767 * of the context node in document order; thus the context node is the first
7768 * node on the axis, and the first child of the context node is the second node
7769 * on the axis
7770 *
7771 * Returns the next element following that axis
7772 */
7773xmlNodePtr
7774xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007775 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007776 if (cur == NULL) {
7777 if (ctxt->context->node == NULL)
7778 return(NULL);
7779 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7780 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7781 return(NULL);
7782 return(ctxt->context->node);
7783 }
7784
7785 return(xmlXPathNextDescendant(ctxt, cur));
7786}
7787
7788/**
7789 * xmlXPathNextParent:
7790 * @ctxt: the XPath Parser context
7791 * @cur: the current node in the traversal
7792 *
7793 * Traversal function for the "parent" direction
7794 * The parent axis contains the parent of the context node, if there is one.
7795 *
7796 * Returns the next element following that axis
7797 */
7798xmlNodePtr
7799xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007800 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007801 /*
7802 * the parent of an attribute or namespace node is the element
7803 * to which the attribute or namespace node is attached
7804 * Namespace handling !!!
7805 */
7806 if (cur == NULL) {
7807 if (ctxt->context->node == NULL) return(NULL);
7808 switch (ctxt->context->node->type) {
7809 case XML_ELEMENT_NODE:
7810 case XML_TEXT_NODE:
7811 case XML_CDATA_SECTION_NODE:
7812 case XML_ENTITY_REF_NODE:
7813 case XML_ENTITY_NODE:
7814 case XML_PI_NODE:
7815 case XML_COMMENT_NODE:
7816 case XML_NOTATION_NODE:
7817 case XML_DTD_NODE:
7818 case XML_ELEMENT_DECL:
7819 case XML_ATTRIBUTE_DECL:
7820 case XML_XINCLUDE_START:
7821 case XML_XINCLUDE_END:
7822 case XML_ENTITY_DECL:
7823 if (ctxt->context->node->parent == NULL)
7824 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007825 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007826 ((ctxt->context->node->parent->name[0] == ' ') ||
7827 (xmlStrEqual(ctxt->context->node->parent->name,
7828 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007829 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007830 return(ctxt->context->node->parent);
7831 case XML_ATTRIBUTE_NODE: {
7832 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7833
7834 return(att->parent);
7835 }
7836 case XML_DOCUMENT_NODE:
7837 case XML_DOCUMENT_TYPE_NODE:
7838 case XML_DOCUMENT_FRAG_NODE:
7839 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007840#ifdef LIBXML_DOCB_ENABLED
7841 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007842#endif
7843 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007844 case XML_NAMESPACE_DECL: {
7845 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7846
7847 if ((ns->next != NULL) &&
7848 (ns->next->type != XML_NAMESPACE_DECL))
7849 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00007850 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007851 }
Owen Taylor3473f882001-02-23 17:55:21 +00007852 }
7853 }
7854 return(NULL);
7855}
7856
7857/**
7858 * xmlXPathNextAncestor:
7859 * @ctxt: the XPath Parser context
7860 * @cur: the current node in the traversal
7861 *
7862 * Traversal function for the "ancestor" direction
7863 * the ancestor axis contains the ancestors of the context node; the ancestors
7864 * of the context node consist of the parent of context node and the parent's
7865 * parent and so on; the nodes are ordered in reverse document order; thus the
7866 * parent is the first node on the axis, and the parent's parent is the second
7867 * node on the axis
7868 *
7869 * Returns the next element following that axis
7870 */
7871xmlNodePtr
7872xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007873 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007874 /*
7875 * the parent of an attribute or namespace node is the element
7876 * to which the attribute or namespace node is attached
7877 * !!!!!!!!!!!!!
7878 */
7879 if (cur == NULL) {
7880 if (ctxt->context->node == NULL) return(NULL);
7881 switch (ctxt->context->node->type) {
7882 case XML_ELEMENT_NODE:
7883 case XML_TEXT_NODE:
7884 case XML_CDATA_SECTION_NODE:
7885 case XML_ENTITY_REF_NODE:
7886 case XML_ENTITY_NODE:
7887 case XML_PI_NODE:
7888 case XML_COMMENT_NODE:
7889 case XML_DTD_NODE:
7890 case XML_ELEMENT_DECL:
7891 case XML_ATTRIBUTE_DECL:
7892 case XML_ENTITY_DECL:
7893 case XML_NOTATION_NODE:
7894 case XML_XINCLUDE_START:
7895 case XML_XINCLUDE_END:
7896 if (ctxt->context->node->parent == NULL)
7897 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007898 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007899 ((ctxt->context->node->parent->name[0] == ' ') ||
7900 (xmlStrEqual(ctxt->context->node->parent->name,
7901 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007902 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007903 return(ctxt->context->node->parent);
7904 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007905 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00007906
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007907 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00007908 }
7909 case XML_DOCUMENT_NODE:
7910 case XML_DOCUMENT_TYPE_NODE:
7911 case XML_DOCUMENT_FRAG_NODE:
7912 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007913#ifdef LIBXML_DOCB_ENABLED
7914 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007915#endif
7916 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007917 case XML_NAMESPACE_DECL: {
7918 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7919
7920 if ((ns->next != NULL) &&
7921 (ns->next->type != XML_NAMESPACE_DECL))
7922 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00007923 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00007924 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007925 }
Owen Taylor3473f882001-02-23 17:55:21 +00007926 }
7927 return(NULL);
7928 }
7929 if (cur == ctxt->context->doc->children)
7930 return((xmlNodePtr) ctxt->context->doc);
7931 if (cur == (xmlNodePtr) ctxt->context->doc)
7932 return(NULL);
7933 switch (cur->type) {
7934 case XML_ELEMENT_NODE:
7935 case XML_TEXT_NODE:
7936 case XML_CDATA_SECTION_NODE:
7937 case XML_ENTITY_REF_NODE:
7938 case XML_ENTITY_NODE:
7939 case XML_PI_NODE:
7940 case XML_COMMENT_NODE:
7941 case XML_NOTATION_NODE:
7942 case XML_DTD_NODE:
7943 case XML_ELEMENT_DECL:
7944 case XML_ATTRIBUTE_DECL:
7945 case XML_ENTITY_DECL:
7946 case XML_XINCLUDE_START:
7947 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007948 if (cur->parent == NULL)
7949 return(NULL);
7950 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007951 ((cur->parent->name[0] == ' ') ||
7952 (xmlStrEqual(cur->parent->name,
7953 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007954 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007955 return(cur->parent);
7956 case XML_ATTRIBUTE_NODE: {
7957 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7958
7959 return(att->parent);
7960 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00007961 case XML_NAMESPACE_DECL: {
7962 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7963
7964 if ((ns->next != NULL) &&
7965 (ns->next->type != XML_NAMESPACE_DECL))
7966 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00007967 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00007968 return(NULL);
7969 }
Owen Taylor3473f882001-02-23 17:55:21 +00007970 case XML_DOCUMENT_NODE:
7971 case XML_DOCUMENT_TYPE_NODE:
7972 case XML_DOCUMENT_FRAG_NODE:
7973 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007974#ifdef LIBXML_DOCB_ENABLED
7975 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007976#endif
7977 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007978 }
7979 return(NULL);
7980}
7981
7982/**
7983 * xmlXPathNextAncestorOrSelf:
7984 * @ctxt: the XPath Parser context
7985 * @cur: the current node in the traversal
7986 *
7987 * Traversal function for the "ancestor-or-self" direction
7988 * he ancestor-or-self axis contains the context node and ancestors of
7989 * the context node in reverse document order; thus the context node is
7990 * the first node on the axis, and the context node's parent the second;
7991 * parent here is defined the same as with the parent axis.
7992 *
7993 * Returns the next element following that axis
7994 */
7995xmlNodePtr
7996xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007997 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007998 if (cur == NULL)
7999 return(ctxt->context->node);
8000 return(xmlXPathNextAncestor(ctxt, cur));
8001}
8002
8003/**
8004 * xmlXPathNextFollowingSibling:
8005 * @ctxt: the XPath Parser context
8006 * @cur: the current node in the traversal
8007 *
8008 * Traversal function for the "following-sibling" direction
8009 * The following-sibling axis contains the following siblings of the context
8010 * node in document order.
8011 *
8012 * Returns the next element following that axis
8013 */
8014xmlNodePtr
8015xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008016 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008017 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8018 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8019 return(NULL);
8020 if (cur == (xmlNodePtr) ctxt->context->doc)
8021 return(NULL);
8022 if (cur == NULL)
8023 return(ctxt->context->node->next);
8024 return(cur->next);
8025}
8026
8027/**
8028 * xmlXPathNextPrecedingSibling:
8029 * @ctxt: the XPath Parser context
8030 * @cur: the current node in the traversal
8031 *
8032 * Traversal function for the "preceding-sibling" direction
8033 * The preceding-sibling axis contains the preceding siblings of the context
8034 * node in reverse document order; the first preceding sibling is first on the
8035 * axis; the sibling preceding that node is the second on the axis and so on.
8036 *
8037 * Returns the next element following that axis
8038 */
8039xmlNodePtr
8040xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008041 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008042 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8043 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8044 return(NULL);
8045 if (cur == (xmlNodePtr) ctxt->context->doc)
8046 return(NULL);
8047 if (cur == NULL)
8048 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008049 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8050 cur = cur->prev;
8051 if (cur == NULL)
8052 return(ctxt->context->node->prev);
8053 }
Owen Taylor3473f882001-02-23 17:55:21 +00008054 return(cur->prev);
8055}
8056
8057/**
8058 * xmlXPathNextFollowing:
8059 * @ctxt: the XPath Parser context
8060 * @cur: the current node in the traversal
8061 *
8062 * Traversal function for the "following" direction
8063 * The following axis contains all nodes in the same document as the context
8064 * node that are after the context node in document order, excluding any
8065 * descendants and excluding attribute nodes and namespace nodes; the nodes
8066 * are ordered in document order
8067 *
8068 * Returns the next element following that axis
8069 */
8070xmlNodePtr
8071xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008072 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008073 if (cur != NULL && cur->children != NULL)
8074 return cur->children ;
8075 if (cur == NULL) cur = ctxt->context->node;
8076 if (cur == NULL) return(NULL) ; /* ERROR */
8077 if (cur->next != NULL) return(cur->next) ;
8078 do {
8079 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00008080 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00008081 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8082 if (cur->next != NULL) return(cur->next);
8083 } while (cur != NULL);
8084 return(cur);
8085}
8086
8087/*
8088 * xmlXPathIsAncestor:
8089 * @ancestor: the ancestor node
8090 * @node: the current node
8091 *
8092 * Check that @ancestor is a @node's ancestor
8093 *
8094 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8095 */
8096static int
8097xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8098 if ((ancestor == NULL) || (node == NULL)) return(0);
8099 /* nodes need to be in the same document */
8100 if (ancestor->doc != node->doc) return(0);
8101 /* avoid searching if ancestor or node is the root node */
8102 if (ancestor == (xmlNodePtr) node->doc) return(1);
8103 if (node == (xmlNodePtr) ancestor->doc) return(0);
8104 while (node->parent != NULL) {
8105 if (node->parent == ancestor)
8106 return(1);
8107 node = node->parent;
8108 }
8109 return(0);
8110}
8111
8112/**
8113 * xmlXPathNextPreceding:
8114 * @ctxt: the XPath Parser context
8115 * @cur: the current node in the traversal
8116 *
8117 * Traversal function for the "preceding" direction
8118 * the preceding axis contains all nodes in the same document as the context
8119 * node that are before the context node in document order, excluding any
8120 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8121 * ordered in reverse document order
8122 *
8123 * Returns the next element following that axis
8124 */
8125xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00008126xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8127{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008128 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008129 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008130 cur = ctxt->context->node;
8131 if (cur == NULL)
8132 return (NULL);
8133 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8134 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00008135 do {
8136 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008137 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8138 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008139 }
8140
8141 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008142 if (cur == NULL)
8143 return (NULL);
8144 if (cur == ctxt->context->doc->children)
8145 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008146 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00008147 return (cur);
8148}
8149
8150/**
8151 * xmlXPathNextPrecedingInternal:
8152 * @ctxt: the XPath Parser context
8153 * @cur: the current node in the traversal
8154 *
8155 * Traversal function for the "preceding" direction
8156 * the preceding axis contains all nodes in the same document as the context
8157 * node that are before the context node in document order, excluding any
8158 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8159 * ordered in reverse document order
8160 * This is a faster implementation but internal only since it requires a
8161 * state kept in the parser context: ctxt->ancestor.
8162 *
8163 * Returns the next element following that axis
8164 */
8165static xmlNodePtr
8166xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8167 xmlNodePtr cur)
8168{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008169 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008170 if (cur == NULL) {
8171 cur = ctxt->context->node;
8172 if (cur == NULL)
8173 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00008174 if (cur->type == XML_NAMESPACE_DECL)
8175 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008176 ctxt->ancestor = cur->parent;
8177 }
8178 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8179 cur = cur->prev;
8180 while (cur->prev == NULL) {
8181 cur = cur->parent;
8182 if (cur == NULL)
8183 return (NULL);
8184 if (cur == ctxt->context->doc->children)
8185 return (NULL);
8186 if (cur != ctxt->ancestor)
8187 return (cur);
8188 ctxt->ancestor = cur->parent;
8189 }
8190 cur = cur->prev;
8191 while (cur->last != NULL)
8192 cur = cur->last;
8193 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008194}
8195
8196/**
8197 * xmlXPathNextNamespace:
8198 * @ctxt: the XPath Parser context
8199 * @cur: the current attribute in the traversal
8200 *
8201 * Traversal function for the "namespace" direction
8202 * the namespace axis contains the namespace nodes of the context node;
8203 * the order of nodes on this axis is implementation-defined; the axis will
8204 * be empty unless the context node is an element
8205 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008206 * We keep the XML namespace node at the end of the list.
8207 *
Owen Taylor3473f882001-02-23 17:55:21 +00008208 * Returns the next element following that axis
8209 */
8210xmlNodePtr
8211xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008212 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008213 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00008214 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008215 if (ctxt->context->tmpNsList != NULL)
8216 xmlFree(ctxt->context->tmpNsList);
8217 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00008218 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008219 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00008220 if (ctxt->context->tmpNsList != NULL) {
8221 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8222 ctxt->context->tmpNsNr++;
8223 }
8224 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008225 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008226 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00008227 if (ctxt->context->tmpNsNr > 0) {
8228 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8229 } else {
8230 if (ctxt->context->tmpNsList != NULL)
8231 xmlFree(ctxt->context->tmpNsList);
8232 ctxt->context->tmpNsList = NULL;
8233 return(NULL);
8234 }
Owen Taylor3473f882001-02-23 17:55:21 +00008235}
8236
8237/**
8238 * xmlXPathNextAttribute:
8239 * @ctxt: the XPath Parser context
8240 * @cur: the current attribute in the traversal
8241 *
8242 * Traversal function for the "attribute" direction
8243 * TODO: support DTD inherited default attributes
8244 *
8245 * Returns the next element following that axis
8246 */
8247xmlNodePtr
8248xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008249 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00008250 if (ctxt->context->node == NULL)
8251 return(NULL);
8252 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8253 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008254 if (cur == NULL) {
8255 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8256 return(NULL);
8257 return((xmlNodePtr)ctxt->context->node->properties);
8258 }
8259 return((xmlNodePtr)cur->next);
8260}
8261
8262/************************************************************************
8263 * *
8264 * NodeTest Functions *
8265 * *
8266 ************************************************************************/
8267
Owen Taylor3473f882001-02-23 17:55:21 +00008268#define IS_FUNCTION 200
8269
Owen Taylor3473f882001-02-23 17:55:21 +00008270
8271/************************************************************************
8272 * *
8273 * Implicit tree core function library *
8274 * *
8275 ************************************************************************/
8276
8277/**
8278 * xmlXPathRoot:
8279 * @ctxt: the XPath Parser context
8280 *
8281 * Initialize the context to the root of the document
8282 */
8283void
8284xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008285 if ((ctxt == NULL) || (ctxt->context == NULL))
8286 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008287 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008288 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8289 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008290}
8291
8292/************************************************************************
8293 * *
8294 * The explicit core function library *
8295 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8296 * *
8297 ************************************************************************/
8298
8299
8300/**
8301 * xmlXPathLastFunction:
8302 * @ctxt: the XPath Parser context
8303 * @nargs: the number of arguments
8304 *
8305 * Implement the last() XPath function
8306 * number last()
8307 * The last function returns the number of nodes in the context node list.
8308 */
8309void
8310xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8311 CHECK_ARITY(0);
8312 if (ctxt->context->contextSize >= 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008313 valuePush(ctxt,
8314 xmlXPathCacheNewFloat(ctxt->context,
8315 (double) ctxt->context->contextSize));
Owen Taylor3473f882001-02-23 17:55:21 +00008316#ifdef DEBUG_EXPR
8317 xmlGenericError(xmlGenericErrorContext,
8318 "last() : %d\n", ctxt->context->contextSize);
8319#endif
8320 } else {
8321 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8322 }
8323}
8324
8325/**
8326 * xmlXPathPositionFunction:
8327 * @ctxt: the XPath Parser context
8328 * @nargs: the number of arguments
8329 *
8330 * Implement the position() XPath function
8331 * number position()
8332 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008333 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00008334 * will be equal to last().
8335 */
8336void
8337xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8338 CHECK_ARITY(0);
8339 if (ctxt->context->proximityPosition >= 0) {
8340 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008341 xmlXPathCacheNewFloat(ctxt->context,
8342 (double) ctxt->context->proximityPosition));
Owen Taylor3473f882001-02-23 17:55:21 +00008343#ifdef DEBUG_EXPR
8344 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8345 ctxt->context->proximityPosition);
8346#endif
8347 } else {
8348 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8349 }
8350}
8351
8352/**
8353 * xmlXPathCountFunction:
8354 * @ctxt: the XPath Parser context
8355 * @nargs: the number of arguments
8356 *
8357 * Implement the count() XPath function
8358 * number count(node-set)
8359 */
8360void
8361xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8362 xmlXPathObjectPtr cur;
8363
8364 CHECK_ARITY(1);
8365 if ((ctxt->value == NULL) ||
8366 ((ctxt->value->type != XPATH_NODESET) &&
8367 (ctxt->value->type != XPATH_XSLT_TREE)))
8368 XP_ERROR(XPATH_INVALID_TYPE);
8369 cur = valuePop(ctxt);
8370
Daniel Veillard911f49a2001-04-07 15:39:35 +00008371 if ((cur == NULL) || (cur->nodesetval == NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008372 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00008373 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008374 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8375 (double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00008376 } else {
8377 if ((cur->nodesetval->nodeNr != 1) ||
8378 (cur->nodesetval->nodeTab == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008379 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00008380 } else {
8381 xmlNodePtr tmp;
8382 int i = 0;
8383
8384 tmp = cur->nodesetval->nodeTab[0];
8385 if (tmp != NULL) {
8386 tmp = tmp->children;
8387 while (tmp != NULL) {
8388 tmp = tmp->next;
8389 i++;
8390 }
8391 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008392 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
Daniel Veillardfe703322001-08-14 12:18:09 +00008393 }
8394 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008395 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008396}
8397
8398/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008399 * xmlXPathGetElementsByIds:
8400 * @doc: the document
8401 * @ids: a whitespace separated list of IDs
8402 *
8403 * Selects elements by their unique ID.
8404 *
8405 * Returns a node-set of selected elements.
8406 */
8407static xmlNodeSetPtr
8408xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8409 xmlNodeSetPtr ret;
8410 const xmlChar *cur = ids;
8411 xmlChar *ID;
8412 xmlAttrPtr attr;
8413 xmlNodePtr elem = NULL;
8414
Daniel Veillard7a985a12003-07-06 17:57:42 +00008415 if (ids == NULL) return(NULL);
8416
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008417 ret = xmlXPathNodeSetCreate(NULL);
8418
William M. Brack76e95df2003-10-18 16:20:14 +00008419 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008420 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008421 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00008422 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008423
8424 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00008425 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00008426 /*
8427 * We used to check the fact that the value passed
8428 * was an NCName, but this generated much troubles for
8429 * me and Aleksey Sanin, people blatantly violated that
8430 * constaint, like Visa3D spec.
8431 * if (xmlValidateNCName(ID, 1) == 0)
8432 */
8433 attr = xmlGetID(doc, ID);
8434 if (attr != NULL) {
8435 if (attr->type == XML_ATTRIBUTE_NODE)
8436 elem = attr->parent;
8437 else if (attr->type == XML_ELEMENT_NODE)
8438 elem = (xmlNodePtr) attr;
8439 else
8440 elem = NULL;
8441 if (elem != NULL)
8442 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00008443 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008444 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00008445 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008446
William M. Brack76e95df2003-10-18 16:20:14 +00008447 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008448 ids = cur;
8449 }
8450 return(ret);
8451}
8452
8453/**
Owen Taylor3473f882001-02-23 17:55:21 +00008454 * xmlXPathIdFunction:
8455 * @ctxt: the XPath Parser context
8456 * @nargs: the number of arguments
8457 *
8458 * Implement the id() XPath function
8459 * node-set id(object)
8460 * The id function selects elements by their unique ID
8461 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8462 * then the result is the union of the result of applying id to the
8463 * string value of each of the nodes in the argument node-set. When the
8464 * argument to id is of any other type, the argument is converted to a
8465 * string as if by a call to the string function; the string is split
8466 * into a whitespace-separated list of tokens (whitespace is any sequence
8467 * of characters matching the production S); the result is a node-set
8468 * containing the elements in the same document as the context node that
8469 * have a unique ID equal to any of the tokens in the list.
8470 */
8471void
8472xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008473 xmlChar *tokens;
8474 xmlNodeSetPtr ret;
8475 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00008476
8477 CHECK_ARITY(1);
8478 obj = valuePop(ctxt);
8479 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00008480 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008481 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00008482 int i;
8483
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008484 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008485
Daniel Veillard911f49a2001-04-07 15:39:35 +00008486 if (obj->nodesetval != NULL) {
8487 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008488 tokens =
8489 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8490 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8491 ret = xmlXPathNodeSetMerge(ret, ns);
8492 xmlXPathFreeNodeSet(ns);
8493 if (tokens != NULL)
8494 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00008495 }
Owen Taylor3473f882001-02-23 17:55:21 +00008496 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008497 xmlXPathReleaseObject(ctxt->context, obj);
8498 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00008499 return;
8500 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008501 obj = xmlXPathCacheConvertString(ctxt->context, obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008502 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008503 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8504 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00008505 return;
8506}
8507
8508/**
8509 * xmlXPathLocalNameFunction:
8510 * @ctxt: the XPath Parser context
8511 * @nargs: the number of arguments
8512 *
8513 * Implement the local-name() XPath function
8514 * string local-name(node-set?)
8515 * The local-name function returns a string containing the local part
8516 * of the name of the node in the argument node-set that is first in
8517 * document order. If the node-set is empty or the first node has no
8518 * name, an empty string is returned. If the argument is omitted it
8519 * defaults to the context node.
8520 */
8521void
8522xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8523 xmlXPathObjectPtr cur;
8524
Daniel Veillarda82b1822004-11-08 16:24:57 +00008525 if (ctxt == NULL) return;
8526
Owen Taylor3473f882001-02-23 17:55:21 +00008527 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008528 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8529 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008530 nargs = 1;
8531 }
8532
8533 CHECK_ARITY(1);
8534 if ((ctxt->value == NULL) ||
8535 ((ctxt->value->type != XPATH_NODESET) &&
8536 (ctxt->value->type != XPATH_XSLT_TREE)))
8537 XP_ERROR(XPATH_INVALID_TYPE);
8538 cur = valuePop(ctxt);
8539
Daniel Veillard911f49a2001-04-07 15:39:35 +00008540 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008541 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008542 } else {
8543 int i = 0; /* Should be first in document order !!!!! */
8544 switch (cur->nodesetval->nodeTab[i]->type) {
8545 case XML_ELEMENT_NODE:
8546 case XML_ATTRIBUTE_NODE:
8547 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008548 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008549 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008550 else
8551 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008552 xmlXPathCacheNewString(ctxt->context,
8553 cur->nodesetval->nodeTab[i]->name));
Owen Taylor3473f882001-02-23 17:55:21 +00008554 break;
8555 case XML_NAMESPACE_DECL:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008556 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008557 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8558 break;
8559 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008560 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008561 }
8562 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008563 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008564}
8565
8566/**
8567 * xmlXPathNamespaceURIFunction:
8568 * @ctxt: the XPath Parser context
8569 * @nargs: the number of arguments
8570 *
8571 * Implement the namespace-uri() XPath function
8572 * string namespace-uri(node-set?)
8573 * The namespace-uri function returns a string containing the
8574 * namespace URI of the expanded name of the node in the argument
8575 * node-set that is first in document order. If the node-set is empty,
8576 * the first node has no name, or the expanded name has no namespace
8577 * URI, an empty string is returned. If the argument is omitted it
8578 * defaults to the context node.
8579 */
8580void
8581xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8582 xmlXPathObjectPtr cur;
8583
Daniel Veillarda82b1822004-11-08 16:24:57 +00008584 if (ctxt == NULL) return;
8585
Owen Taylor3473f882001-02-23 17:55:21 +00008586 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008587 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8588 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008589 nargs = 1;
8590 }
8591 CHECK_ARITY(1);
8592 if ((ctxt->value == NULL) ||
8593 ((ctxt->value->type != XPATH_NODESET) &&
8594 (ctxt->value->type != XPATH_XSLT_TREE)))
8595 XP_ERROR(XPATH_INVALID_TYPE);
8596 cur = valuePop(ctxt);
8597
Daniel Veillard911f49a2001-04-07 15:39:35 +00008598 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008599 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008600 } else {
8601 int i = 0; /* Should be first in document order !!!!! */
8602 switch (cur->nodesetval->nodeTab[i]->type) {
8603 case XML_ELEMENT_NODE:
8604 case XML_ATTRIBUTE_NODE:
8605 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008606 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008607 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008608 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008609 cur->nodesetval->nodeTab[i]->ns->href));
8610 break;
8611 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008612 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008613 }
8614 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008615 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008616}
8617
8618/**
8619 * xmlXPathNameFunction:
8620 * @ctxt: the XPath Parser context
8621 * @nargs: the number of arguments
8622 *
8623 * Implement the name() XPath function
8624 * string name(node-set?)
8625 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008626 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00008627 * order. The QName must represent the name with respect to the namespace
8628 * declarations in effect on the node whose name is being represented.
8629 * Typically, this will be the form in which the name occurred in the XML
8630 * source. This need not be the case if there are namespace declarations
8631 * in effect on the node that associate multiple prefixes with the same
8632 * namespace. However, an implementation may include information about
8633 * the original prefix in its representation of nodes; in this case, an
8634 * implementation can ensure that the returned string is always the same
8635 * as the QName used in the XML source. If the argument it omitted it
8636 * defaults to the context node.
8637 * Libxml keep the original prefix so the "real qualified name" used is
8638 * returned.
8639 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008640static void
Daniel Veillard04383752001-07-08 14:27:15 +00008641xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8642{
Owen Taylor3473f882001-02-23 17:55:21 +00008643 xmlXPathObjectPtr cur;
8644
8645 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008646 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8647 ctxt->context->node));
Daniel Veillard04383752001-07-08 14:27:15 +00008648 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008649 }
8650
8651 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00008652 if ((ctxt->value == NULL) ||
8653 ((ctxt->value->type != XPATH_NODESET) &&
8654 (ctxt->value->type != XPATH_XSLT_TREE)))
8655 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00008656 cur = valuePop(ctxt);
8657
Daniel Veillard911f49a2001-04-07 15:39:35 +00008658 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008659 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008660 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00008661 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00008662
Daniel Veillard04383752001-07-08 14:27:15 +00008663 switch (cur->nodesetval->nodeTab[i]->type) {
8664 case XML_ELEMENT_NODE:
8665 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008666 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008667 valuePush(ctxt,
8668 xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008669 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8670 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008671 valuePush(ctxt,
8672 xmlXPathCacheNewString(ctxt->context,
8673 cur->nodesetval->nodeTab[i]->name));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008674 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00008675 xmlChar *fullname;
8676
8677 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8678 cur->nodesetval->nodeTab[i]->ns->prefix,
8679 NULL, 0);
8680 if (fullname == cur->nodesetval->nodeTab[i]->name)
8681 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8682 if (fullname == NULL) {
8683 XP_ERROR(XPATH_MEMORY_ERROR);
8684 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008685 valuePush(ctxt, xmlXPathCacheWrapString(
8686 ctxt->context, fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00008687 }
8688 break;
8689 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008690 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8691 cur->nodesetval->nodeTab[i]));
Daniel Veillard04383752001-07-08 14:27:15 +00008692 xmlXPathLocalNameFunction(ctxt, 1);
8693 }
Owen Taylor3473f882001-02-23 17:55:21 +00008694 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008695 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008696}
8697
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008698
8699/**
Owen Taylor3473f882001-02-23 17:55:21 +00008700 * xmlXPathStringFunction:
8701 * @ctxt: the XPath Parser context
8702 * @nargs: the number of arguments
8703 *
8704 * Implement the string() XPath function
8705 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00008706 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00008707 * - A node-set is converted to a string by returning the value of
8708 * the node in the node-set that is first in document order.
8709 * If the node-set is empty, an empty string is returned.
8710 * - A number is converted to a string as follows
8711 * + NaN is converted to the string NaN
8712 * + positive zero is converted to the string 0
8713 * + negative zero is converted to the string 0
8714 * + positive infinity is converted to the string Infinity
8715 * + negative infinity is converted to the string -Infinity
8716 * + if the number is an integer, the number is represented in
8717 * decimal form as a Number with no decimal point and no leading
8718 * zeros, preceded by a minus sign (-) if the number is negative
8719 * + otherwise, the number is represented in decimal form as a
8720 * Number including a decimal point with at least one digit
8721 * before the decimal point and at least one digit after the
8722 * decimal point, preceded by a minus sign (-) if the number
8723 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008724 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00008725 * before the decimal point; beyond the one required digit
8726 * after the decimal point there must be as many, but only as
8727 * many, more digits as are needed to uniquely distinguish the
8728 * number from all other IEEE 754 numeric values.
8729 * - The boolean false value is converted to the string false.
8730 * The boolean true value is converted to the string true.
8731 *
8732 * If the argument is omitted, it defaults to a node-set with the
8733 * context node as its only member.
8734 */
8735void
8736xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8737 xmlXPathObjectPtr cur;
8738
Daniel Veillarda82b1822004-11-08 16:24:57 +00008739 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008740 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008741 valuePush(ctxt,
8742 xmlXPathCacheWrapString(ctxt->context,
8743 xmlXPathCastNodeToString(ctxt->context->node)));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008744 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008745 }
8746
8747 CHECK_ARITY(1);
8748 cur = valuePop(ctxt);
8749 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008750 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00008751}
8752
8753/**
8754 * xmlXPathStringLengthFunction:
8755 * @ctxt: the XPath Parser context
8756 * @nargs: the number of arguments
8757 *
8758 * Implement the string-length() XPath function
8759 * number string-length(string?)
8760 * The string-length returns the number of characters in the string
8761 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8762 * the context node converted to a string, in other words the value
8763 * of the context node.
8764 */
8765void
8766xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8767 xmlXPathObjectPtr cur;
8768
8769 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008770 if ((ctxt == NULL) || (ctxt->context == NULL))
8771 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008772 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008773 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008774 } else {
8775 xmlChar *content;
8776
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008777 content = xmlXPathCastNodeToString(ctxt->context->node);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008778 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8779 xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00008780 xmlFree(content);
8781 }
8782 return;
8783 }
8784 CHECK_ARITY(1);
8785 CAST_TO_STRING;
8786 CHECK_TYPE(XPATH_STRING);
8787 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008788 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8789 xmlUTF8Strlen(cur->stringval)));
8790 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008791}
8792
8793/**
8794 * xmlXPathConcatFunction:
8795 * @ctxt: the XPath Parser context
8796 * @nargs: the number of arguments
8797 *
8798 * Implement the concat() XPath function
8799 * string concat(string, string, string*)
8800 * The concat function returns the concatenation of its arguments.
8801 */
8802void
8803xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8804 xmlXPathObjectPtr cur, newobj;
8805 xmlChar *tmp;
8806
Daniel Veillarda82b1822004-11-08 16:24:57 +00008807 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008808 if (nargs < 2) {
8809 CHECK_ARITY(2);
8810 }
8811
8812 CAST_TO_STRING;
8813 cur = valuePop(ctxt);
8814 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008815 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008816 return;
8817 }
8818 nargs--;
8819
8820 while (nargs > 0) {
8821 CAST_TO_STRING;
8822 newobj = valuePop(ctxt);
8823 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008824 xmlXPathReleaseObject(ctxt->context, newobj);
8825 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008826 XP_ERROR(XPATH_INVALID_TYPE);
8827 }
8828 tmp = xmlStrcat(newobj->stringval, cur->stringval);
8829 newobj->stringval = cur->stringval;
8830 cur->stringval = tmp;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008831 xmlXPathReleaseObject(ctxt->context, newobj);
Owen Taylor3473f882001-02-23 17:55:21 +00008832 nargs--;
8833 }
8834 valuePush(ctxt, cur);
8835}
8836
8837/**
8838 * xmlXPathContainsFunction:
8839 * @ctxt: the XPath Parser context
8840 * @nargs: the number of arguments
8841 *
8842 * Implement the contains() XPath function
8843 * boolean contains(string, string)
8844 * The contains function returns true if the first argument string
8845 * contains the second argument string, and otherwise returns false.
8846 */
8847void
8848xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8849 xmlXPathObjectPtr hay, needle;
8850
8851 CHECK_ARITY(2);
8852 CAST_TO_STRING;
8853 CHECK_TYPE(XPATH_STRING);
8854 needle = valuePop(ctxt);
8855 CAST_TO_STRING;
8856 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008857
Owen Taylor3473f882001-02-23 17:55:21 +00008858 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008859 xmlXPathReleaseObject(ctxt->context, hay);
8860 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008861 XP_ERROR(XPATH_INVALID_TYPE);
8862 }
8863 if (xmlStrstr(hay->stringval, needle->stringval))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008864 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00008865 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008866 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8867 xmlXPathReleaseObject(ctxt->context, hay);
8868 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008869}
8870
8871/**
8872 * xmlXPathStartsWithFunction:
8873 * @ctxt: the XPath Parser context
8874 * @nargs: the number of arguments
8875 *
8876 * Implement the starts-with() XPath function
8877 * boolean starts-with(string, string)
8878 * The starts-with function returns true if the first argument string
8879 * starts with the second argument string, and otherwise returns false.
8880 */
8881void
8882xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8883 xmlXPathObjectPtr hay, needle;
8884 int n;
8885
8886 CHECK_ARITY(2);
8887 CAST_TO_STRING;
8888 CHECK_TYPE(XPATH_STRING);
8889 needle = valuePop(ctxt);
8890 CAST_TO_STRING;
8891 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008892
Owen Taylor3473f882001-02-23 17:55:21 +00008893 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008894 xmlXPathReleaseObject(ctxt->context, hay);
8895 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008896 XP_ERROR(XPATH_INVALID_TYPE);
8897 }
8898 n = xmlStrlen(needle->stringval);
8899 if (xmlStrncmp(hay->stringval, needle->stringval, n))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008900 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008901 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008902 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8903 xmlXPathReleaseObject(ctxt->context, hay);
8904 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008905}
8906
8907/**
8908 * xmlXPathSubstringFunction:
8909 * @ctxt: the XPath Parser context
8910 * @nargs: the number of arguments
8911 *
8912 * Implement the substring() XPath function
8913 * string substring(string, number, number?)
8914 * The substring function returns the substring of the first argument
8915 * starting at the position specified in the second argument with
8916 * length specified in the third argument. For example,
8917 * substring("12345",2,3) returns "234". If the third argument is not
8918 * specified, it returns the substring starting at the position specified
8919 * in the second argument and continuing to the end of the string. For
8920 * example, substring("12345",2) returns "2345". More precisely, each
8921 * character in the string (see [3.6 Strings]) is considered to have a
8922 * numeric position: the position of the first character is 1, the position
8923 * of the second character is 2 and so on. The returned substring contains
8924 * those characters for which the position of the character is greater than
8925 * or equal to the second argument and, if the third argument is specified,
8926 * less than the sum of the second and third arguments; the comparisons
8927 * and addition used for the above follow the standard IEEE 754 rules. Thus:
8928 * - substring("12345", 1.5, 2.6) returns "234"
8929 * - substring("12345", 0, 3) returns "12"
8930 * - substring("12345", 0 div 0, 3) returns ""
8931 * - substring("12345", 1, 0 div 0) returns ""
8932 * - substring("12345", -42, 1 div 0) returns "12345"
8933 * - substring("12345", -1 div 0, 1 div 0) returns ""
8934 */
8935void
8936xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8937 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00008938 double le=0, in;
8939 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00008940 xmlChar *ret;
8941
Owen Taylor3473f882001-02-23 17:55:21 +00008942 if (nargs < 2) {
8943 CHECK_ARITY(2);
8944 }
8945 if (nargs > 3) {
8946 CHECK_ARITY(3);
8947 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008948 /*
8949 * take care of possible last (position) argument
8950 */
Owen Taylor3473f882001-02-23 17:55:21 +00008951 if (nargs == 3) {
8952 CAST_TO_NUMBER;
8953 CHECK_TYPE(XPATH_NUMBER);
8954 len = valuePop(ctxt);
8955 le = len->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008956 xmlXPathReleaseObject(ctxt->context, len);
Owen Taylor3473f882001-02-23 17:55:21 +00008957 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008958
Owen Taylor3473f882001-02-23 17:55:21 +00008959 CAST_TO_NUMBER;
8960 CHECK_TYPE(XPATH_NUMBER);
8961 start = valuePop(ctxt);
8962 in = start->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008963 xmlXPathReleaseObject(ctxt->context, start);
Owen Taylor3473f882001-02-23 17:55:21 +00008964 CAST_TO_STRING;
8965 CHECK_TYPE(XPATH_STRING);
8966 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00008967 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00008968
Daniel Veillard97ac1312001-05-30 19:14:17 +00008969 /*
8970 * If last pos not present, calculate last position
8971 */
Daniel Veillard9e412302002-06-10 15:59:44 +00008972 if (nargs != 3) {
8973 le = (double)m;
8974 if (in < 1.0)
8975 in = 1.0;
8976 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008977
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008978 /* Need to check for the special cases where either
8979 * the index is NaN, the length is NaN, or both
8980 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00008981 */
Daniel Veillard9e412302002-06-10 15:59:44 +00008982 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008983 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00008984 * To meet the requirements of the spec, the arguments
8985 * must be converted to integer format before
8986 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008987 *
Daniel Veillard9e412302002-06-10 15:59:44 +00008988 * First we go to integer form, rounding up
8989 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008990 */
8991 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00008992 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00008993
Daniel Veillard9e412302002-06-10 15:59:44 +00008994 if (xmlXPathIsInf(le) == 1) {
8995 l = m;
8996 if (i < 1)
8997 i = 1;
8998 }
8999 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9000 l = 0;
9001 else {
9002 l = (int) le;
9003 if (((double)l)+0.5 <= le) l++;
9004 }
9005
9006 /* Now we normalize inidices */
9007 i -= 1;
9008 l += i;
9009 if (i < 0)
9010 i = 0;
9011 if (l > m)
9012 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00009013
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009014 /* number of chars to copy */
9015 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00009016
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009017 ret = xmlUTF8Strsub(str->stringval, i, l);
9018 }
9019 else {
9020 ret = NULL;
9021 }
Owen Taylor3473f882001-02-23 17:55:21 +00009022 if (ret == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009023 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00009024 else {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009025 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009026 xmlFree(ret);
9027 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009028 xmlXPathReleaseObject(ctxt->context, str);
Owen Taylor3473f882001-02-23 17:55:21 +00009029}
9030
9031/**
9032 * xmlXPathSubstringBeforeFunction:
9033 * @ctxt: the XPath Parser context
9034 * @nargs: the number of arguments
9035 *
9036 * Implement the substring-before() XPath function
9037 * string substring-before(string, string)
9038 * The substring-before function returns the substring of the first
9039 * argument string that precedes the first occurrence of the second
9040 * argument string in the first argument string, or the empty string
9041 * if the first argument string does not contain the second argument
9042 * string. For example, substring-before("1999/04/01","/") returns 1999.
9043 */
9044void
9045xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9046 xmlXPathObjectPtr str;
9047 xmlXPathObjectPtr find;
9048 xmlBufferPtr target;
9049 const xmlChar *point;
9050 int offset;
9051
9052 CHECK_ARITY(2);
9053 CAST_TO_STRING;
9054 find = valuePop(ctxt);
9055 CAST_TO_STRING;
9056 str = valuePop(ctxt);
9057
9058 target = xmlBufferCreate();
9059 if (target) {
9060 point = xmlStrstr(str->stringval, find->stringval);
9061 if (point) {
9062 offset = (int)(point - str->stringval);
9063 xmlBufferAdd(target, str->stringval, offset);
9064 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009065 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9066 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00009067 xmlBufferFree(target);
9068 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009069 xmlXPathReleaseObject(ctxt->context, str);
9070 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009071}
9072
9073/**
9074 * xmlXPathSubstringAfterFunction:
9075 * @ctxt: the XPath Parser context
9076 * @nargs: the number of arguments
9077 *
9078 * Implement the substring-after() XPath function
9079 * string substring-after(string, string)
9080 * The substring-after function returns the substring of the first
9081 * argument string that follows the first occurrence of the second
9082 * argument string in the first argument string, or the empty stringi
9083 * if the first argument string does not contain the second argument
9084 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9085 * and substring-after("1999/04/01","19") returns 99/04/01.
9086 */
9087void
9088xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9089 xmlXPathObjectPtr str;
9090 xmlXPathObjectPtr find;
9091 xmlBufferPtr target;
9092 const xmlChar *point;
9093 int offset;
9094
9095 CHECK_ARITY(2);
9096 CAST_TO_STRING;
9097 find = valuePop(ctxt);
9098 CAST_TO_STRING;
9099 str = valuePop(ctxt);
9100
9101 target = xmlBufferCreate();
9102 if (target) {
9103 point = xmlStrstr(str->stringval, find->stringval);
9104 if (point) {
9105 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9106 xmlBufferAdd(target, &str->stringval[offset],
9107 xmlStrlen(str->stringval) - offset);
9108 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009109 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9110 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00009111 xmlBufferFree(target);
9112 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009113 xmlXPathReleaseObject(ctxt->context, str);
9114 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009115}
9116
9117/**
9118 * xmlXPathNormalizeFunction:
9119 * @ctxt: the XPath Parser context
9120 * @nargs: the number of arguments
9121 *
9122 * Implement the normalize-space() XPath function
9123 * string normalize-space(string?)
9124 * The normalize-space function returns the argument string with white
9125 * space normalized by stripping leading and trailing whitespace
9126 * and replacing sequences of whitespace characters by a single
9127 * space. Whitespace characters are the same allowed by the S production
9128 * in XML. If the argument is omitted, it defaults to the context
9129 * node converted to a string, in other words the value of the context node.
9130 */
9131void
9132xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9133 xmlXPathObjectPtr obj = NULL;
9134 xmlChar *source = NULL;
9135 xmlBufferPtr target;
9136 xmlChar blank;
9137
Daniel Veillarda82b1822004-11-08 16:24:57 +00009138 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009139 if (nargs == 0) {
9140 /* Use current context node */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009141 valuePush(ctxt,
9142 xmlXPathCacheWrapString(ctxt->context,
9143 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00009144 nargs = 1;
9145 }
9146
9147 CHECK_ARITY(1);
9148 CAST_TO_STRING;
9149 CHECK_TYPE(XPATH_STRING);
9150 obj = valuePop(ctxt);
9151 source = obj->stringval;
9152
9153 target = xmlBufferCreate();
9154 if (target && source) {
9155
9156 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00009157 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00009158 source++;
9159
9160 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9161 blank = 0;
9162 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00009163 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009164 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00009165 } else {
9166 if (blank) {
9167 xmlBufferAdd(target, &blank, 1);
9168 blank = 0;
9169 }
9170 xmlBufferAdd(target, source, 1);
9171 }
9172 source++;
9173 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009174 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9175 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00009176 xmlBufferFree(target);
9177 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009178 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00009179}
9180
9181/**
9182 * xmlXPathTranslateFunction:
9183 * @ctxt: the XPath Parser context
9184 * @nargs: the number of arguments
9185 *
9186 * Implement the translate() XPath function
9187 * string translate(string, string, string)
9188 * The translate function returns the first argument string with
9189 * occurrences of characters in the second argument string replaced
9190 * by the character at the corresponding position in the third argument
9191 * string. For example, translate("bar","abc","ABC") returns the string
9192 * BAr. If there is a character in the second argument string with no
9193 * character at a corresponding position in the third argument string
9194 * (because the second argument string is longer than the third argument
9195 * string), then occurrences of that character in the first argument
9196 * string are removed. For example, translate("--aaa--","abc-","ABC")
9197 * returns "AAA". If a character occurs more than once in second
9198 * argument string, then the first occurrence determines the replacement
9199 * character. If the third argument string is longer than the second
9200 * argument string, then excess characters are ignored.
9201 */
9202void
9203xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00009204 xmlXPathObjectPtr str;
9205 xmlXPathObjectPtr from;
9206 xmlXPathObjectPtr to;
9207 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009208 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009209 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00009210 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009211 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00009212
Daniel Veillarde043ee12001-04-16 14:08:07 +00009213 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00009214
Daniel Veillarde043ee12001-04-16 14:08:07 +00009215 CAST_TO_STRING;
9216 to = valuePop(ctxt);
9217 CAST_TO_STRING;
9218 from = valuePop(ctxt);
9219 CAST_TO_STRING;
9220 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009221
Daniel Veillarde043ee12001-04-16 14:08:07 +00009222 target = xmlBufferCreate();
9223 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009224 max = xmlUTF8Strlen(to->stringval);
9225 for (cptr = str->stringval; (ch=*cptr); ) {
9226 offset = xmlUTF8Strloc(from->stringval, cptr);
9227 if (offset >= 0) {
9228 if (offset < max) {
9229 point = xmlUTF8Strpos(to->stringval, offset);
9230 if (point)
9231 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
9232 }
9233 } else
9234 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9235
9236 /* Step to next character in input */
9237 cptr++;
9238 if ( ch & 0x80 ) {
9239 /* if not simple ascii, verify proper format */
9240 if ( (ch & 0xc0) != 0xc0 ) {
9241 xmlGenericError(xmlGenericErrorContext,
9242 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9243 break;
9244 }
9245 /* then skip over remaining bytes for this char */
9246 while ( (ch <<= 1) & 0x80 )
9247 if ( (*cptr++ & 0xc0) != 0x80 ) {
9248 xmlGenericError(xmlGenericErrorContext,
9249 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9250 break;
9251 }
9252 if (ch & 0x80) /* must have had error encountered */
9253 break;
9254 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00009255 }
Owen Taylor3473f882001-02-23 17:55:21 +00009256 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009257 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9258 xmlBufferContent(target)));
Daniel Veillarde043ee12001-04-16 14:08:07 +00009259 xmlBufferFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009260 xmlXPathReleaseObject(ctxt->context, str);
9261 xmlXPathReleaseObject(ctxt->context, from);
9262 xmlXPathReleaseObject(ctxt->context, to);
Owen Taylor3473f882001-02-23 17:55:21 +00009263}
9264
9265/**
9266 * xmlXPathBooleanFunction:
9267 * @ctxt: the XPath Parser context
9268 * @nargs: the number of arguments
9269 *
9270 * Implement the boolean() XPath function
9271 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00009272 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00009273 * - a number is true if and only if it is neither positive or
9274 * negative zero nor NaN
9275 * - a node-set is true if and only if it is non-empty
9276 * - a string is true if and only if its length is non-zero
9277 */
9278void
9279xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9280 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00009281
9282 CHECK_ARITY(1);
9283 cur = valuePop(ctxt);
9284 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009285 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009286 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009287}
9288
9289/**
9290 * xmlXPathNotFunction:
9291 * @ctxt: the XPath Parser context
9292 * @nargs: the number of arguments
9293 *
9294 * Implement the not() XPath function
9295 * boolean not(boolean)
9296 * The not function returns true if its argument is false,
9297 * and false otherwise.
9298 */
9299void
9300xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9301 CHECK_ARITY(1);
9302 CAST_TO_BOOLEAN;
9303 CHECK_TYPE(XPATH_BOOLEAN);
9304 ctxt->value->boolval = ! ctxt->value->boolval;
9305}
9306
9307/**
9308 * xmlXPathTrueFunction:
9309 * @ctxt: the XPath Parser context
9310 * @nargs: the number of arguments
9311 *
9312 * Implement the true() XPath function
9313 * boolean true()
9314 */
9315void
9316xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9317 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009318 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009319}
9320
9321/**
9322 * xmlXPathFalseFunction:
9323 * @ctxt: the XPath Parser context
9324 * @nargs: the number of arguments
9325 *
9326 * Implement the false() XPath function
9327 * boolean false()
9328 */
9329void
9330xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9331 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009332 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009333}
9334
9335/**
9336 * xmlXPathLangFunction:
9337 * @ctxt: the XPath Parser context
9338 * @nargs: the number of arguments
9339 *
9340 * Implement the lang() XPath function
9341 * boolean lang(string)
9342 * The lang function returns true or false depending on whether the
9343 * language of the context node as specified by xml:lang attributes
9344 * is the same as or is a sublanguage of the language specified by
9345 * the argument string. The language of the context node is determined
9346 * by the value of the xml:lang attribute on the context node, or, if
9347 * the context node has no xml:lang attribute, by the value of the
9348 * xml:lang attribute on the nearest ancestor of the context node that
9349 * has an xml:lang attribute. If there is no such attribute, then lang
9350 * returns false. If there is such an attribute, then lang returns
9351 * true if the attribute value is equal to the argument ignoring case,
9352 * or if there is some suffix starting with - such that the attribute
9353 * value is equal to the argument ignoring that suffix of the attribute
9354 * value and ignoring case.
9355 */
9356void
9357xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009358 xmlXPathObjectPtr val = NULL;
9359 const xmlChar *theLang = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009360 const xmlChar *lang;
9361 int ret = 0;
9362 int i;
9363
9364 CHECK_ARITY(1);
9365 CAST_TO_STRING;
9366 CHECK_TYPE(XPATH_STRING);
9367 val = valuePop(ctxt);
9368 lang = val->stringval;
9369 theLang = xmlNodeGetLang(ctxt->context->node);
9370 if ((theLang != NULL) && (lang != NULL)) {
9371 for (i = 0;lang[i] != 0;i++)
9372 if (toupper(lang[i]) != toupper(theLang[i]))
9373 goto not_equal;
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009374 if ((theLang[i] == 0) || (theLang[i] == '-'))
9375 ret = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009376 }
9377not_equal:
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009378 if (theLang != NULL)
9379 xmlFree((void *)theLang);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009380
9381 xmlXPathReleaseObject(ctxt->context, val);
9382 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009383}
9384
9385/**
9386 * xmlXPathNumberFunction:
9387 * @ctxt: the XPath Parser context
9388 * @nargs: the number of arguments
9389 *
9390 * Implement the number() XPath function
9391 * number number(object?)
9392 */
9393void
9394xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9395 xmlXPathObjectPtr cur;
9396 double res;
9397
Daniel Veillarda82b1822004-11-08 16:24:57 +00009398 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009399 if (nargs == 0) {
9400 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009401 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
Owen Taylor3473f882001-02-23 17:55:21 +00009402 } else {
9403 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9404
9405 res = xmlXPathStringEvalNumber(content);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009406 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
Owen Taylor3473f882001-02-23 17:55:21 +00009407 xmlFree(content);
9408 }
9409 return;
9410 }
9411
9412 CHECK_ARITY(1);
9413 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009414 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00009415}
9416
9417/**
9418 * xmlXPathSumFunction:
9419 * @ctxt: the XPath Parser context
9420 * @nargs: the number of arguments
9421 *
9422 * Implement the sum() XPath function
9423 * number sum(node-set)
9424 * The sum function returns the sum of the values of the nodes in
9425 * the argument node-set.
9426 */
9427void
9428xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9429 xmlXPathObjectPtr cur;
9430 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009431 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00009432
9433 CHECK_ARITY(1);
9434 if ((ctxt->value == NULL) ||
9435 ((ctxt->value->type != XPATH_NODESET) &&
9436 (ctxt->value->type != XPATH_XSLT_TREE)))
9437 XP_ERROR(XPATH_INVALID_TYPE);
9438 cur = valuePop(ctxt);
9439
William M. Brack08171912003-12-29 02:52:11 +00009440 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009441 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9442 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00009443 }
9444 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009445 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9446 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009447}
9448
William M. Brack3d426662005-04-19 14:40:28 +00009449/*
9450 * To assure working code on multiple platforms, we want to only depend
9451 * upon the characteristic truncation of converting a floating point value
9452 * to an integer. Unfortunately, because of the different storage sizes
9453 * of our internal floating point value (double) and integer (int), we
9454 * can't directly convert (see bug 301162). This macro is a messy
9455 * 'workaround'
9456 */
9457#define XTRUNC(f, v) \
9458 f = fmod((v), INT_MAX); \
9459 f = (v) - (f) + (double)((int)(f));
9460
Owen Taylor3473f882001-02-23 17:55:21 +00009461/**
9462 * xmlXPathFloorFunction:
9463 * @ctxt: the XPath Parser context
9464 * @nargs: the number of arguments
9465 *
9466 * Implement the floor() XPath function
9467 * number floor(number)
9468 * The floor function returns the largest (closest to positive infinity)
9469 * number that is not greater than the argument and that is an integer.
9470 */
9471void
9472xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009473 double f;
9474
Owen Taylor3473f882001-02-23 17:55:21 +00009475 CHECK_ARITY(1);
9476 CAST_TO_NUMBER;
9477 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009478
William M. Brack3d426662005-04-19 14:40:28 +00009479 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009480 if (f != ctxt->value->floatval) {
9481 if (ctxt->value->floatval > 0)
9482 ctxt->value->floatval = f;
9483 else
9484 ctxt->value->floatval = f - 1;
9485 }
Owen Taylor3473f882001-02-23 17:55:21 +00009486}
9487
9488/**
9489 * xmlXPathCeilingFunction:
9490 * @ctxt: the XPath Parser context
9491 * @nargs: the number of arguments
9492 *
9493 * Implement the ceiling() XPath function
9494 * number ceiling(number)
9495 * The ceiling function returns the smallest (closest to negative infinity)
9496 * number that is not less than the argument and that is an integer.
9497 */
9498void
9499xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9500 double f;
9501
9502 CHECK_ARITY(1);
9503 CAST_TO_NUMBER;
9504 CHECK_TYPE(XPATH_NUMBER);
9505
9506#if 0
9507 ctxt->value->floatval = ceil(ctxt->value->floatval);
9508#else
William M. Brack3d426662005-04-19 14:40:28 +00009509 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009510 if (f != ctxt->value->floatval) {
9511 if (ctxt->value->floatval > 0)
9512 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009513 else {
9514 if (ctxt->value->floatval < 0 && f == 0)
9515 ctxt->value->floatval = xmlXPathNZERO;
9516 else
9517 ctxt->value->floatval = f;
9518 }
9519
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009520 }
Owen Taylor3473f882001-02-23 17:55:21 +00009521#endif
9522}
9523
9524/**
9525 * xmlXPathRoundFunction:
9526 * @ctxt: the XPath Parser context
9527 * @nargs: the number of arguments
9528 *
9529 * Implement the round() XPath function
9530 * number round(number)
9531 * The round function returns the number that is closest to the
9532 * argument and that is an integer. If there are two such numbers,
9533 * then the one that is even is returned.
9534 */
9535void
9536xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9537 double f;
9538
9539 CHECK_ARITY(1);
9540 CAST_TO_NUMBER;
9541 CHECK_TYPE(XPATH_NUMBER);
9542
Daniel Veillardcda96922001-08-21 10:56:31 +00009543 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9544 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9545 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009546 (ctxt->value->floatval == 0.0))
9547 return;
9548
William M. Brack3d426662005-04-19 14:40:28 +00009549 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009550 if (ctxt->value->floatval < 0) {
9551 if (ctxt->value->floatval < f - 0.5)
9552 ctxt->value->floatval = f - 1;
9553 else
9554 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009555 if (ctxt->value->floatval == 0)
9556 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009557 } else {
9558 if (ctxt->value->floatval < f + 0.5)
9559 ctxt->value->floatval = f;
9560 else
9561 ctxt->value->floatval = f + 1;
9562 }
Owen Taylor3473f882001-02-23 17:55:21 +00009563}
9564
9565/************************************************************************
9566 * *
9567 * The Parser *
9568 * *
9569 ************************************************************************/
9570
9571/*
William M. Brack08171912003-12-29 02:52:11 +00009572 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00009573 * implementation.
9574 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009575static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009576static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009577static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009578static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00009579static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9580 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00009581
9582/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00009583 * xmlXPathCurrentChar:
9584 * @ctxt: the XPath parser context
9585 * @cur: pointer to the beginning of the char
9586 * @len: pointer to the length of the char read
9587 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009588 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00009589 * bytes in the input buffer.
9590 *
Daniel Veillard60087f32001-10-10 09:45:09 +00009591 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00009592 */
9593
9594static int
9595xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9596 unsigned char c;
9597 unsigned int val;
9598 const xmlChar *cur;
9599
9600 if (ctxt == NULL)
9601 return(0);
9602 cur = ctxt->cur;
9603
9604 /*
9605 * We are supposed to handle UTF8, check it's valid
9606 * From rfc2044: encoding of the Unicode values on UTF-8:
9607 *
9608 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9609 * 0000 0000-0000 007F 0xxxxxxx
9610 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
9611 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
9612 *
9613 * Check for the 0x110000 limit too
9614 */
9615 c = *cur;
9616 if (c & 0x80) {
9617 if ((cur[1] & 0xc0) != 0x80)
9618 goto encoding_error;
9619 if ((c & 0xe0) == 0xe0) {
9620
9621 if ((cur[2] & 0xc0) != 0x80)
9622 goto encoding_error;
9623 if ((c & 0xf0) == 0xf0) {
9624 if (((c & 0xf8) != 0xf0) ||
9625 ((cur[3] & 0xc0) != 0x80))
9626 goto encoding_error;
9627 /* 4-byte code */
9628 *len = 4;
9629 val = (cur[0] & 0x7) << 18;
9630 val |= (cur[1] & 0x3f) << 12;
9631 val |= (cur[2] & 0x3f) << 6;
9632 val |= cur[3] & 0x3f;
9633 } else {
9634 /* 3-byte code */
9635 *len = 3;
9636 val = (cur[0] & 0xf) << 12;
9637 val |= (cur[1] & 0x3f) << 6;
9638 val |= cur[2] & 0x3f;
9639 }
9640 } else {
9641 /* 2-byte code */
9642 *len = 2;
9643 val = (cur[0] & 0x1f) << 6;
9644 val |= cur[1] & 0x3f;
9645 }
9646 if (!IS_CHAR(val)) {
9647 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9648 }
9649 return(val);
9650 } else {
9651 /* 1-byte code */
9652 *len = 1;
9653 return((int) *cur);
9654 }
9655encoding_error:
9656 /*
William M. Brack08171912003-12-29 02:52:11 +00009657 * If we detect an UTF8 error that probably means that the
9658 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00009659 * declaration header. Report the error and switch the encoding
9660 * to ISO-Latin-1 (if you don't like this policy, just declare the
9661 * encoding !)
9662 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00009663 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00009664 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009665}
9666
9667/**
Owen Taylor3473f882001-02-23 17:55:21 +00009668 * xmlXPathParseNCName:
9669 * @ctxt: the XPath Parser context
9670 *
9671 * parse an XML namespace non qualified name.
9672 *
9673 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9674 *
9675 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9676 * CombiningChar | Extender
9677 *
9678 * Returns the namespace name or NULL
9679 */
9680
9681xmlChar *
9682xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00009683 const xmlChar *in;
9684 xmlChar *ret;
9685 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009686
Daniel Veillarda82b1822004-11-08 16:24:57 +00009687 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00009688 /*
9689 * Accelerator for simple ASCII names
9690 */
9691 in = ctxt->cur;
9692 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9693 ((*in >= 0x41) && (*in <= 0x5A)) ||
9694 (*in == '_')) {
9695 in++;
9696 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9697 ((*in >= 0x41) && (*in <= 0x5A)) ||
9698 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00009699 (*in == '_') || (*in == '.') ||
9700 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00009701 in++;
9702 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9703 (*in == '[') || (*in == ']') || (*in == ':') ||
9704 (*in == '@') || (*in == '*')) {
9705 count = in - ctxt->cur;
9706 if (count == 0)
9707 return(NULL);
9708 ret = xmlStrndup(ctxt->cur, count);
9709 ctxt->cur = in;
9710 return(ret);
9711 }
9712 }
9713 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009714}
9715
Daniel Veillard2156a562001-04-28 12:24:34 +00009716
Owen Taylor3473f882001-02-23 17:55:21 +00009717/**
9718 * xmlXPathParseQName:
9719 * @ctxt: the XPath Parser context
9720 * @prefix: a xmlChar **
9721 *
9722 * parse an XML qualified name
9723 *
9724 * [NS 5] QName ::= (Prefix ':')? LocalPart
9725 *
9726 * [NS 6] Prefix ::= NCName
9727 *
9728 * [NS 7] LocalPart ::= NCName
9729 *
9730 * Returns the function returns the local part, and prefix is updated
9731 * to get the Prefix if any.
9732 */
9733
Daniel Veillard56a4cb82001-03-24 17:00:36 +00009734static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00009735xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9736 xmlChar *ret = NULL;
9737
9738 *prefix = NULL;
9739 ret = xmlXPathParseNCName(ctxt);
9740 if (CUR == ':') {
9741 *prefix = ret;
9742 NEXT;
9743 ret = xmlXPathParseNCName(ctxt);
9744 }
9745 return(ret);
9746}
9747
9748/**
9749 * xmlXPathParseName:
9750 * @ctxt: the XPath Parser context
9751 *
9752 * parse an XML name
9753 *
9754 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9755 * CombiningChar | Extender
9756 *
9757 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9758 *
9759 * Returns the namespace name or NULL
9760 */
9761
9762xmlChar *
9763xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009764 const xmlChar *in;
9765 xmlChar *ret;
9766 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009767
Daniel Veillarda82b1822004-11-08 16:24:57 +00009768 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009769 /*
9770 * Accelerator for simple ASCII names
9771 */
9772 in = ctxt->cur;
9773 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9774 ((*in >= 0x41) && (*in <= 0x5A)) ||
9775 (*in == '_') || (*in == ':')) {
9776 in++;
9777 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9778 ((*in >= 0x41) && (*in <= 0x5A)) ||
9779 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00009780 (*in == '_') || (*in == '-') ||
9781 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00009782 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00009783 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009784 count = in - ctxt->cur;
9785 ret = xmlStrndup(ctxt->cur, count);
9786 ctxt->cur = in;
9787 return(ret);
9788 }
9789 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009790 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009791}
9792
Daniel Veillard61d80a22001-04-27 17:13:01 +00009793static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00009794xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009795 xmlChar buf[XML_MAX_NAMELEN + 5];
9796 int len = 0, l;
9797 int c;
9798
9799 /*
9800 * Handler for more complex cases
9801 */
9802 c = CUR_CHAR(l);
9803 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00009804 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9805 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00009806 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00009807 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009808 return(NULL);
9809 }
9810
9811 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9812 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9813 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00009814 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009815 (IS_COMBINING(c)) ||
9816 (IS_EXTENDER(c)))) {
9817 COPY_BUF(l,buf,len,c);
9818 NEXTL(l);
9819 c = CUR_CHAR(l);
9820 if (len >= XML_MAX_NAMELEN) {
9821 /*
9822 * Okay someone managed to make a huge name, so he's ready to pay
9823 * for the processing speed.
9824 */
9825 xmlChar *buffer;
9826 int max = len * 2;
9827
Daniel Veillard3c908dc2003-04-19 00:07:51 +00009828 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009829 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009830 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009831 }
9832 memcpy(buffer, buf, len);
9833 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9834 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00009835 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009836 (IS_COMBINING(c)) ||
9837 (IS_EXTENDER(c))) {
9838 if (len + 10 > max) {
9839 max *= 2;
9840 buffer = (xmlChar *) xmlRealloc(buffer,
9841 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009842 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009843 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009844 }
9845 }
9846 COPY_BUF(l,buffer,len,c);
9847 NEXTL(l);
9848 c = CUR_CHAR(l);
9849 }
9850 buffer[len] = 0;
9851 return(buffer);
9852 }
9853 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009854 if (len == 0)
9855 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009856 return(xmlStrndup(buf, len));
9857}
Daniel Veillard3cd72402002-05-13 10:33:30 +00009858
9859#define MAX_FRAC 20
9860
William M. Brack372a4452004-02-17 13:09:23 +00009861/*
9862 * These are used as divisors for the fractional part of a number.
9863 * Since the table includes 1.0 (representing '0' fractional digits),
9864 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
9865 */
9866static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +00009867 1.0, 10.0, 100.0, 1000.0, 10000.0,
9868 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
9869 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
9870 100000000000000.0,
9871 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +00009872 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +00009873};
9874
Owen Taylor3473f882001-02-23 17:55:21 +00009875/**
9876 * xmlXPathStringEvalNumber:
9877 * @str: A string to scan
9878 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00009879 * [30a] Float ::= Number ('e' Digits?)?
9880 *
Owen Taylor3473f882001-02-23 17:55:21 +00009881 * [30] Number ::= Digits ('.' Digits?)?
9882 * | '.' Digits
9883 * [31] Digits ::= [0-9]+
9884 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009885 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00009886 * In complement of the Number expression, this function also handles
9887 * negative values : '-' Number.
9888 *
9889 * Returns the double value.
9890 */
9891double
9892xmlXPathStringEvalNumber(const xmlChar *str) {
9893 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00009894 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009895 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009896 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009897 int exponent = 0;
9898 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009899#ifdef __GNUC__
9900 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00009901 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009902#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00009903 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00009904 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009905 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
9906 return(xmlXPathNAN);
9907 }
9908 if (*cur == '-') {
9909 isneg = 1;
9910 cur++;
9911 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00009912
9913#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009914 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00009915 * tmp/temp is a workaround against a gcc compiler bug
9916 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009917 */
Daniel Veillard7b416132002-03-07 08:36:03 +00009918 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009919 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00009920 ret = ret * 10;
9921 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00009922 ok = 1;
9923 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00009924 temp = (double) tmp;
9925 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00009926 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00009927#else
Daniel Veillard7b416132002-03-07 08:36:03 +00009928 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009929 while ((*cur >= '0') && (*cur <= '9')) {
9930 ret = ret * 10 + (*cur - '0');
9931 ok = 1;
9932 cur++;
9933 }
9934#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009935
Owen Taylor3473f882001-02-23 17:55:21 +00009936 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00009937 int v, frac = 0;
9938 double fraction = 0;
9939
Owen Taylor3473f882001-02-23 17:55:21 +00009940 cur++;
9941 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
9942 return(xmlXPathNAN);
9943 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00009944 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
9945 v = (*cur - '0');
9946 fraction = fraction * 10 + v;
9947 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009948 cur++;
9949 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00009950 fraction /= my_pow10[frac];
9951 ret = ret + fraction;
9952 while ((*cur >= '0') && (*cur <= '9'))
9953 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009954 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00009955 if ((*cur == 'e') || (*cur == 'E')) {
9956 cur++;
9957 if (*cur == '-') {
9958 is_exponent_negative = 1;
9959 cur++;
William M. Brack99127052004-05-24 02:52:28 +00009960 } else if (*cur == '+') {
9961 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009962 }
9963 while ((*cur >= '0') && (*cur <= '9')) {
9964 exponent = exponent * 10 + (*cur - '0');
9965 cur++;
9966 }
9967 }
William M. Brack76e95df2003-10-18 16:20:14 +00009968 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009969 if (*cur != 0) return(xmlXPathNAN);
9970 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009971 if (is_exponent_negative) exponent = -exponent;
9972 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00009973 return(ret);
9974}
9975
9976/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009977 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00009978 * @ctxt: the XPath Parser context
9979 *
9980 * [30] Number ::= Digits ('.' Digits?)?
9981 * | '.' Digits
9982 * [31] Digits ::= [0-9]+
9983 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009984 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00009985 *
9986 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009987static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009988xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
9989{
Owen Taylor3473f882001-02-23 17:55:21 +00009990 double ret = 0.0;
9991 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00009992 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009993 int exponent = 0;
9994 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00009995#ifdef __GNUC__
9996 unsigned long tmp = 0;
9997 double temp;
9998#endif
Owen Taylor3473f882001-02-23 17:55:21 +00009999
10000 CHECK_ERROR;
10001 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10002 XP_ERROR(XPATH_NUMBER_ERROR);
10003 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010004#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010005 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010006 * tmp/temp is a workaround against a gcc compiler bug
10007 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010008 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010009 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010010 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010011 ret = ret * 10;
10012 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010013 ok = 1;
10014 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +000010015 temp = (double) tmp;
10016 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010017 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010018#else
10019 ret = 0;
10020 while ((CUR >= '0') && (CUR <= '9')) {
10021 ret = ret * 10 + (CUR - '0');
10022 ok = 1;
10023 NEXT;
10024 }
10025#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010026 if (CUR == '.') {
10027 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010028 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10029 XP_ERROR(XPATH_NUMBER_ERROR);
10030 }
10031 while ((CUR >= '0') && (CUR <= '9')) {
10032 mult /= 10;
10033 ret = ret + (CUR - '0') * mult;
10034 NEXT;
10035 }
Owen Taylor3473f882001-02-23 17:55:21 +000010036 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010037 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010038 NEXT;
10039 if (CUR == '-') {
10040 is_exponent_negative = 1;
10041 NEXT;
William M. Brack99127052004-05-24 02:52:28 +000010042 } else if (CUR == '+') {
10043 NEXT;
10044 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010045 while ((CUR >= '0') && (CUR <= '9')) {
10046 exponent = exponent * 10 + (CUR - '0');
10047 NEXT;
10048 }
10049 if (is_exponent_negative)
10050 exponent = -exponent;
10051 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +000010052 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010053 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010054 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010055}
10056
10057/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010058 * xmlXPathParseLiteral:
10059 * @ctxt: the XPath Parser context
10060 *
10061 * Parse a Literal
10062 *
10063 * [29] Literal ::= '"' [^"]* '"'
10064 * | "'" [^']* "'"
10065 *
10066 * Returns the value found or NULL in case of error
10067 */
10068static xmlChar *
10069xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10070 const xmlChar *q;
10071 xmlChar *ret = NULL;
10072
10073 if (CUR == '"') {
10074 NEXT;
10075 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010076 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010077 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010078 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010079 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010080 } else {
10081 ret = xmlStrndup(q, CUR_PTR - q);
10082 NEXT;
10083 }
10084 } else if (CUR == '\'') {
10085 NEXT;
10086 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010087 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010088 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010089 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010090 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010091 } else {
10092 ret = xmlStrndup(q, CUR_PTR - q);
10093 NEXT;
10094 }
10095 } else {
Daniel Veillard24505b02005-07-28 23:49:35 +000010096 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010097 }
10098 return(ret);
10099}
10100
10101/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010102 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +000010103 * @ctxt: the XPath Parser context
10104 *
10105 * Parse a Literal and push it on the stack.
10106 *
10107 * [29] Literal ::= '"' [^"]* '"'
10108 * | "'" [^']* "'"
10109 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010110 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +000010111 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010112static void
10113xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010114 const xmlChar *q;
10115 xmlChar *ret = NULL;
10116
10117 if (CUR == '"') {
10118 NEXT;
10119 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010120 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +000010121 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010122 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010123 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10124 } else {
10125 ret = xmlStrndup(q, CUR_PTR - q);
10126 NEXT;
10127 }
10128 } else if (CUR == '\'') {
10129 NEXT;
10130 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010131 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +000010132 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010133 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010134 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10135 } else {
10136 ret = xmlStrndup(q, CUR_PTR - q);
10137 NEXT;
10138 }
10139 } else {
10140 XP_ERROR(XPATH_START_LITERAL_ERROR);
10141 }
10142 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010143 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010144 xmlXPathCacheNewString(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010145 xmlFree(ret);
10146}
10147
10148/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010149 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +000010150 * @ctxt: the XPath Parser context
10151 *
10152 * Parse a VariableReference, evaluate it and push it on the stack.
10153 *
10154 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +000010155 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +000010156 * of any of the types that are possible for the value of an expression,
10157 * and may also be of additional types not specified here.
10158 *
10159 * Early evaluation is possible since:
10160 * The variable bindings [...] used to evaluate a subexpression are
10161 * always the same as those used to evaluate the containing expression.
10162 *
10163 * [36] VariableReference ::= '$' QName
10164 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010165static void
10166xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010167 xmlChar *name;
10168 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010169
10170 SKIP_BLANKS;
10171 if (CUR != '$') {
10172 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10173 }
10174 NEXT;
10175 name = xmlXPathParseQName(ctxt, &prefix);
10176 if (name == NULL) {
10177 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10178 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010179 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010180 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10181 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010182 SKIP_BLANKS;
Daniel Veillardb3d14912005-09-04 20:47:39 +000010183 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10184 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
10185 }
Owen Taylor3473f882001-02-23 17:55:21 +000010186}
10187
10188/**
10189 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +000010190 * @name: a name string
10191 *
10192 * Is the name given a NodeType one.
10193 *
10194 * [38] NodeType ::= 'comment'
10195 * | 'text'
10196 * | 'processing-instruction'
10197 * | 'node'
10198 *
10199 * Returns 1 if true 0 otherwise
10200 */
10201int
10202xmlXPathIsNodeType(const xmlChar *name) {
10203 if (name == NULL)
10204 return(0);
10205
Daniel Veillard1971ee22002-01-31 20:29:19 +000010206 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +000010207 return(1);
10208 if (xmlStrEqual(name, BAD_CAST "text"))
10209 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010210 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +000010211 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010212 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +000010213 return(1);
10214 return(0);
10215}
10216
10217/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010218 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +000010219 * @ctxt: the XPath Parser context
10220 *
10221 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10222 * [17] Argument ::= Expr
10223 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010224 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +000010225 * pushed on the stack
10226 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010227static void
10228xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010229 xmlChar *name;
10230 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010231 int nbargs = 0;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010232 int sort = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010233
10234 name = xmlXPathParseQName(ctxt, &prefix);
10235 if (name == NULL) {
10236 XP_ERROR(XPATH_EXPR_ERROR);
10237 }
10238 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010239#ifdef DEBUG_EXPR
10240 if (prefix == NULL)
10241 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10242 name);
10243 else
10244 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10245 prefix, name);
10246#endif
10247
Owen Taylor3473f882001-02-23 17:55:21 +000010248 if (CUR != '(') {
10249 XP_ERROR(XPATH_EXPR_ERROR);
10250 }
10251 NEXT;
10252 SKIP_BLANKS;
10253
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010254 /*
10255 * Optimization for count(): we don't need the node-set to be sorted.
10256 */
10257 if ((prefix == NULL) && (name[0] == 'c') &&
10258 xmlStrEqual(name, BAD_CAST "count"))
10259 {
10260 sort = 0;
10261 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010262 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +000010263 if (CUR != ')') {
10264 while (CUR != 0) {
10265 int op1 = ctxt->comp->last;
10266 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010267 xmlXPathCompileExpr(ctxt, sort);
Daniel Veillard71f9d732003-01-14 16:07:16 +000010268 CHECK_ERROR;
10269 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10270 nbargs++;
10271 if (CUR == ')') break;
10272 if (CUR != ',') {
10273 XP_ERROR(XPATH_EXPR_ERROR);
10274 }
10275 NEXT;
10276 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010277 }
Owen Taylor3473f882001-02-23 17:55:21 +000010278 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010279 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10280 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010281 NEXT;
10282 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010283}
10284
10285/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010286 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010287 * @ctxt: the XPath Parser context
10288 *
10289 * [15] PrimaryExpr ::= VariableReference
10290 * | '(' Expr ')'
10291 * | Literal
10292 * | Number
10293 * | FunctionCall
10294 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010295 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010296 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010297static void
10298xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010299 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010300 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010301 else if (CUR == '(') {
10302 NEXT;
10303 SKIP_BLANKS;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010304 xmlXPathCompileExpr(ctxt, 1);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010305 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000010306 if (CUR != ')') {
10307 XP_ERROR(XPATH_EXPR_ERROR);
10308 }
10309 NEXT;
10310 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010311 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010312 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010313 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010314 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010315 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010316 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010317 }
10318 SKIP_BLANKS;
10319}
10320
10321/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010322 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010323 * @ctxt: the XPath Parser context
10324 *
10325 * [20] FilterExpr ::= PrimaryExpr
10326 * | FilterExpr Predicate
10327 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010328 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010329 * Square brackets are used to filter expressions in the same way that
10330 * they are used in location paths. It is an error if the expression to
10331 * be filtered does not evaluate to a node-set. The context node list
10332 * used for evaluating the expression in square brackets is the node-set
10333 * to be filtered listed in document order.
10334 */
10335
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010336static void
10337xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10338 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010339 CHECK_ERROR;
10340 SKIP_BLANKS;
10341
10342 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010343 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +000010344 SKIP_BLANKS;
10345 }
10346
10347
10348}
10349
10350/**
10351 * xmlXPathScanName:
10352 * @ctxt: the XPath Parser context
10353 *
10354 * Trickery: parse an XML name but without consuming the input flow
10355 * Needed to avoid insanity in the parser state.
10356 *
10357 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10358 * CombiningChar | Extender
10359 *
10360 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10361 *
10362 * [6] Names ::= Name (S Name)*
10363 *
10364 * Returns the Name parsed or NULL
10365 */
10366
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010367static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +000010368xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +000010369 int len = 0, l;
10370 int c;
Daniel Veillard03226812004-11-01 14:55:21 +000010371 const xmlChar *cur;
10372 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +000010373
Daniel Veillard03226812004-11-01 14:55:21 +000010374 cur = ctxt->cur;
10375
10376 c = CUR_CHAR(l);
10377 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10378 (!IS_LETTER(c) && (c != '_') &&
10379 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010380 return(NULL);
10381 }
10382
Daniel Veillard03226812004-11-01 14:55:21 +000010383 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10384 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10385 (c == '.') || (c == '-') ||
10386 (c == '_') || (c == ':') ||
10387 (IS_COMBINING(c)) ||
10388 (IS_EXTENDER(c)))) {
10389 len += l;
10390 NEXTL(l);
10391 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +000010392 }
Daniel Veillard03226812004-11-01 14:55:21 +000010393 ret = xmlStrndup(cur, ctxt->cur - cur);
10394 ctxt->cur = cur;
10395 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +000010396}
10397
10398/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010399 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010400 * @ctxt: the XPath Parser context
10401 *
10402 * [19] PathExpr ::= LocationPath
10403 * | FilterExpr
10404 * | FilterExpr '/' RelativeLocationPath
10405 * | FilterExpr '//' RelativeLocationPath
10406 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010407 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010408 * The / operator and // operators combine an arbitrary expression
10409 * and a relative location path. It is an error if the expression
10410 * does not evaluate to a node-set.
10411 * The / operator does composition in the same way as when / is
10412 * used in a location path. As in location paths, // is short for
10413 * /descendant-or-self::node()/.
10414 */
10415
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010416static void
10417xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010418 int lc = 1; /* Should we branch to LocationPath ? */
10419 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10420
10421 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010422 if ((CUR == '$') || (CUR == '(') ||
10423 (IS_ASCII_DIGIT(CUR)) ||
10424 (CUR == '\'') || (CUR == '"') ||
10425 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010426 lc = 0;
10427 } else if (CUR == '*') {
10428 /* relative or absolute location path */
10429 lc = 1;
10430 } else if (CUR == '/') {
10431 /* relative or absolute location path */
10432 lc = 1;
10433 } else if (CUR == '@') {
10434 /* relative abbreviated attribute location path */
10435 lc = 1;
10436 } else if (CUR == '.') {
10437 /* relative abbreviated attribute location path */
10438 lc = 1;
10439 } else {
10440 /*
10441 * Problem is finding if we have a name here whether it's:
10442 * - a nodetype
10443 * - a function call in which case it's followed by '('
10444 * - an axis in which case it's followed by ':'
10445 * - a element name
10446 * We do an a priori analysis here rather than having to
10447 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +000010448 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +000010449 * read/write/debug.
10450 */
10451 SKIP_BLANKS;
10452 name = xmlXPathScanName(ctxt);
10453 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10454#ifdef DEBUG_STEP
10455 xmlGenericError(xmlGenericErrorContext,
10456 "PathExpr: Axis\n");
10457#endif
10458 lc = 1;
10459 xmlFree(name);
10460 } else if (name != NULL) {
10461 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +000010462
10463
10464 while (NXT(len) != 0) {
10465 if (NXT(len) == '/') {
10466 /* element name */
10467#ifdef DEBUG_STEP
10468 xmlGenericError(xmlGenericErrorContext,
10469 "PathExpr: AbbrRelLocation\n");
10470#endif
10471 lc = 1;
10472 break;
William M. Brack76e95df2003-10-18 16:20:14 +000010473 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +000010474 /* ignore blanks */
10475 ;
Owen Taylor3473f882001-02-23 17:55:21 +000010476 } else if (NXT(len) == ':') {
10477#ifdef DEBUG_STEP
10478 xmlGenericError(xmlGenericErrorContext,
10479 "PathExpr: AbbrRelLocation\n");
10480#endif
10481 lc = 1;
10482 break;
10483 } else if ((NXT(len) == '(')) {
10484 /* Note Type or Function */
10485 if (xmlXPathIsNodeType(name)) {
10486#ifdef DEBUG_STEP
10487 xmlGenericError(xmlGenericErrorContext,
10488 "PathExpr: Type search\n");
10489#endif
10490 lc = 1;
10491 } else {
10492#ifdef DEBUG_STEP
10493 xmlGenericError(xmlGenericErrorContext,
10494 "PathExpr: function call\n");
10495#endif
10496 lc = 0;
10497 }
10498 break;
10499 } else if ((NXT(len) == '[')) {
10500 /* element name */
10501#ifdef DEBUG_STEP
10502 xmlGenericError(xmlGenericErrorContext,
10503 "PathExpr: AbbrRelLocation\n");
10504#endif
10505 lc = 1;
10506 break;
10507 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10508 (NXT(len) == '=')) {
10509 lc = 1;
10510 break;
10511 } else {
10512 lc = 1;
10513 break;
10514 }
10515 len++;
10516 }
10517 if (NXT(len) == 0) {
10518#ifdef DEBUG_STEP
10519 xmlGenericError(xmlGenericErrorContext,
10520 "PathExpr: AbbrRelLocation\n");
10521#endif
10522 /* element name */
10523 lc = 1;
10524 }
10525 xmlFree(name);
10526 } else {
William M. Brack08171912003-12-29 02:52:11 +000010527 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +000010528 XP_ERROR(XPATH_EXPR_ERROR);
10529 }
10530 }
10531
10532 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010533 if (CUR == '/') {
10534 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10535 } else {
10536 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010537 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010538 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010539 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010540 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010541 CHECK_ERROR;
10542 if ((CUR == '/') && (NXT(1) == '/')) {
10543 SKIP(2);
10544 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010545
10546 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10547 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10548 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10549
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010550 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010551 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010552 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010553 }
10554 }
10555 SKIP_BLANKS;
10556}
10557
10558/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010559 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010560 * @ctxt: the XPath Parser context
10561 *
10562 * [18] UnionExpr ::= PathExpr
10563 * | UnionExpr '|' PathExpr
10564 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010565 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010566 */
10567
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010568static void
10569xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10570 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010571 CHECK_ERROR;
10572 SKIP_BLANKS;
10573 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010574 int op1 = ctxt->comp->last;
10575 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010576
10577 NEXT;
10578 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010579 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010580
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010581 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10582
Owen Taylor3473f882001-02-23 17:55:21 +000010583 SKIP_BLANKS;
10584 }
Owen Taylor3473f882001-02-23 17:55:21 +000010585}
10586
10587/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010588 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010589 * @ctxt: the XPath Parser context
10590 *
10591 * [27] UnaryExpr ::= UnionExpr
10592 * | '-' UnaryExpr
10593 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010594 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010595 */
10596
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010597static void
10598xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010599 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010600 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010601
10602 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +000010603 while (CUR == '-') {
10604 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010605 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010606 NEXT;
10607 SKIP_BLANKS;
10608 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010609
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010610 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010611 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010612 if (found) {
10613 if (minus)
10614 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10615 else
10616 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010617 }
10618}
10619
10620/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010621 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010622 * @ctxt: the XPath Parser context
10623 *
10624 * [26] MultiplicativeExpr ::= UnaryExpr
10625 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10626 * | MultiplicativeExpr 'div' UnaryExpr
10627 * | MultiplicativeExpr 'mod' UnaryExpr
10628 * [34] MultiplyOperator ::= '*'
10629 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010630 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010631 */
10632
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010633static void
10634xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10635 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010636 CHECK_ERROR;
10637 SKIP_BLANKS;
10638 while ((CUR == '*') ||
10639 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10640 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10641 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010642 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010643
10644 if (CUR == '*') {
10645 op = 0;
10646 NEXT;
10647 } else if (CUR == 'd') {
10648 op = 1;
10649 SKIP(3);
10650 } else if (CUR == 'm') {
10651 op = 2;
10652 SKIP(3);
10653 }
10654 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010655 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010656 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010657 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010658 SKIP_BLANKS;
10659 }
10660}
10661
10662/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010663 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010664 * @ctxt: the XPath Parser context
10665 *
10666 * [25] AdditiveExpr ::= MultiplicativeExpr
10667 * | AdditiveExpr '+' MultiplicativeExpr
10668 * | AdditiveExpr '-' MultiplicativeExpr
10669 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010670 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010671 */
10672
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010673static void
10674xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010675
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010676 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010677 CHECK_ERROR;
10678 SKIP_BLANKS;
10679 while ((CUR == '+') || (CUR == '-')) {
10680 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010681 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010682
10683 if (CUR == '+') plus = 1;
10684 else plus = 0;
10685 NEXT;
10686 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010687 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010688 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010689 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010690 SKIP_BLANKS;
10691 }
10692}
10693
10694/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010695 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010696 * @ctxt: the XPath Parser context
10697 *
10698 * [24] RelationalExpr ::= AdditiveExpr
10699 * | RelationalExpr '<' AdditiveExpr
10700 * | RelationalExpr '>' AdditiveExpr
10701 * | RelationalExpr '<=' AdditiveExpr
10702 * | RelationalExpr '>=' AdditiveExpr
10703 *
10704 * A <= B > C is allowed ? Answer from James, yes with
10705 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10706 * which is basically what got implemented.
10707 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010708 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +000010709 * on the stack
10710 */
10711
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010712static void
10713xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10714 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010715 CHECK_ERROR;
10716 SKIP_BLANKS;
10717 while ((CUR == '<') ||
10718 (CUR == '>') ||
10719 ((CUR == '<') && (NXT(1) == '=')) ||
10720 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010721 int inf, strict;
10722 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010723
10724 if (CUR == '<') inf = 1;
10725 else inf = 0;
10726 if (NXT(1) == '=') strict = 0;
10727 else strict = 1;
10728 NEXT;
10729 if (!strict) NEXT;
10730 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010731 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010732 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010733 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +000010734 SKIP_BLANKS;
10735 }
10736}
10737
10738/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010739 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010740 * @ctxt: the XPath Parser context
10741 *
10742 * [23] EqualityExpr ::= RelationalExpr
10743 * | EqualityExpr '=' RelationalExpr
10744 * | EqualityExpr '!=' RelationalExpr
10745 *
10746 * A != B != C is allowed ? Answer from James, yes with
10747 * (RelationalExpr = RelationalExpr) = RelationalExpr
10748 * (RelationalExpr != RelationalExpr) != RelationalExpr
10749 * which is basically what got implemented.
10750 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010751 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010752 *
10753 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010754static void
10755xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10756 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010757 CHECK_ERROR;
10758 SKIP_BLANKS;
10759 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010760 int eq;
10761 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010762
10763 if (CUR == '=') eq = 1;
10764 else eq = 0;
10765 NEXT;
10766 if (!eq) NEXT;
10767 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010768 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010769 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010770 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010771 SKIP_BLANKS;
10772 }
10773}
10774
10775/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010776 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010777 * @ctxt: the XPath Parser context
10778 *
10779 * [22] AndExpr ::= EqualityExpr
10780 * | AndExpr 'and' EqualityExpr
10781 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010782 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010783 *
10784 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010785static void
10786xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10787 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010788 CHECK_ERROR;
10789 SKIP_BLANKS;
10790 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010791 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010792 SKIP(3);
10793 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010794 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010795 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010796 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010797 SKIP_BLANKS;
10798 }
10799}
10800
10801/**
Daniel Veillard591b4be2003-02-09 23:33:36 +000010802 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010803 * @ctxt: the XPath Parser context
10804 *
10805 * [14] Expr ::= OrExpr
10806 * [21] OrExpr ::= AndExpr
10807 * | OrExpr 'or' AndExpr
10808 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010809 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +000010810 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010811static void
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010812xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010813 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010814 CHECK_ERROR;
10815 SKIP_BLANKS;
10816 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010817 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010818 SKIP(2);
10819 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010820 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010821 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010822 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10823 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +000010824 SKIP_BLANKS;
10825 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010826 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010827 /* more ops could be optimized too */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010828 /*
10829 * This is the main place to eliminate sorting for
10830 * operations which don't require a sorted node-set.
10831 * E.g. count().
10832 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010833 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10834 }
Owen Taylor3473f882001-02-23 17:55:21 +000010835}
10836
10837/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010838 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +000010839 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010840 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +000010841 *
10842 * [8] Predicate ::= '[' PredicateExpr ']'
10843 * [9] PredicateExpr ::= Expr
10844 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010845 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +000010846 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010847static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010848xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010849 int op1 = ctxt->comp->last;
10850
10851 SKIP_BLANKS;
10852 if (CUR != '[') {
10853 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10854 }
10855 NEXT;
10856 SKIP_BLANKS;
10857
10858 ctxt->comp->last = -1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000010859 /*
10860 * This call to xmlXPathCompileExpr() will deactivate sorting
10861 * of the predicate result.
10862 * TODO: Sorting is still activated for filters, since I'm not
10863 * sure if needed. Normally sorting should not be needed, since
10864 * a filter can only diminish the number of items in a sequence,
10865 * but won't change its order; so if the initial sequence is sorted,
10866 * subsequent sorting is not needed.
10867 */
10868 if (! filter)
10869 xmlXPathCompileExpr(ctxt, 0);
10870 else
10871 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010872 CHECK_ERROR;
10873
10874 if (CUR != ']') {
10875 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10876 }
10877
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010878 if (filter)
10879 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10880 else
10881 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010882
10883 NEXT;
10884 SKIP_BLANKS;
10885}
10886
10887/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010888 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +000010889 * @ctxt: the XPath Parser context
10890 * @test: pointer to a xmlXPathTestVal
10891 * @type: pointer to a xmlXPathTypeVal
10892 * @prefix: placeholder for a possible name prefix
10893 *
10894 * [7] NodeTest ::= NameTest
10895 * | NodeType '(' ')'
10896 * | 'processing-instruction' '(' Literal ')'
10897 *
10898 * [37] NameTest ::= '*'
10899 * | NCName ':' '*'
10900 * | QName
10901 * [38] NodeType ::= 'comment'
10902 * | 'text'
10903 * | 'processing-instruction'
10904 * | 'node'
10905 *
William M. Brack08171912003-12-29 02:52:11 +000010906 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +000010907 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010908static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010909xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10910 xmlXPathTypeVal *type, const xmlChar **prefix,
10911 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +000010912 int blanks;
10913
10914 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10915 STRANGE;
10916 return(NULL);
10917 }
William M. Brack78637da2003-07-31 14:47:38 +000010918 *type = (xmlXPathTypeVal) 0;
10919 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010920 *prefix = NULL;
10921 SKIP_BLANKS;
10922
10923 if ((name == NULL) && (CUR == '*')) {
10924 /*
10925 * All elements
10926 */
10927 NEXT;
10928 *test = NODE_TEST_ALL;
10929 return(NULL);
10930 }
10931
10932 if (name == NULL)
10933 name = xmlXPathParseNCName(ctxt);
10934 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010935 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010936 }
10937
William M. Brack76e95df2003-10-18 16:20:14 +000010938 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +000010939 SKIP_BLANKS;
10940 if (CUR == '(') {
10941 NEXT;
10942 /*
10943 * NodeType or PI search
10944 */
10945 if (xmlStrEqual(name, BAD_CAST "comment"))
10946 *type = NODE_TYPE_COMMENT;
10947 else if (xmlStrEqual(name, BAD_CAST "node"))
10948 *type = NODE_TYPE_NODE;
10949 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10950 *type = NODE_TYPE_PI;
10951 else if (xmlStrEqual(name, BAD_CAST "text"))
10952 *type = NODE_TYPE_TEXT;
10953 else {
10954 if (name != NULL)
10955 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000010956 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010957 }
10958
10959 *test = NODE_TEST_TYPE;
10960
10961 SKIP_BLANKS;
10962 if (*type == NODE_TYPE_PI) {
10963 /*
10964 * Specific case: search a PI by name.
10965 */
Owen Taylor3473f882001-02-23 17:55:21 +000010966 if (name != NULL)
10967 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +000010968 name = NULL;
10969 if (CUR != ')') {
10970 name = xmlXPathParseLiteral(ctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000010971 CHECK_ERROR NULL;
Daniel Veillarded23b7d2002-05-27 12:16:02 +000010972 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +000010973 SKIP_BLANKS;
10974 }
Owen Taylor3473f882001-02-23 17:55:21 +000010975 }
10976 if (CUR != ')') {
10977 if (name != NULL)
10978 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000010979 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010980 }
10981 NEXT;
10982 return(name);
10983 }
10984 *test = NODE_TEST_NAME;
10985 if ((!blanks) && (CUR == ':')) {
10986 NEXT;
10987
10988 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010989 * Since currently the parser context don't have a
10990 * namespace list associated:
10991 * The namespace name for this prefix can be computed
10992 * only at evaluation time. The compilation is done
10993 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +000010994 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010995#if 0
Owen Taylor3473f882001-02-23 17:55:21 +000010996 *prefix = xmlXPathNsLookup(ctxt->context, name);
10997 if (name != NULL)
10998 xmlFree(name);
10999 if (*prefix == NULL) {
11000 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11001 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011002#else
11003 *prefix = name;
11004#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011005
11006 if (CUR == '*') {
11007 /*
11008 * All elements
11009 */
11010 NEXT;
11011 *test = NODE_TEST_ALL;
11012 return(NULL);
11013 }
11014
11015 name = xmlXPathParseNCName(ctxt);
11016 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011017 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011018 }
11019 }
11020 return(name);
11021}
11022
11023/**
11024 * xmlXPathIsAxisName:
11025 * @name: a preparsed name token
11026 *
11027 * [6] AxisName ::= 'ancestor'
11028 * | 'ancestor-or-self'
11029 * | 'attribute'
11030 * | 'child'
11031 * | 'descendant'
11032 * | 'descendant-or-self'
11033 * | 'following'
11034 * | 'following-sibling'
11035 * | 'namespace'
11036 * | 'parent'
11037 * | 'preceding'
11038 * | 'preceding-sibling'
11039 * | 'self'
11040 *
11041 * Returns the axis or 0
11042 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011043static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +000011044xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +000011045 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011046 switch (name[0]) {
11047 case 'a':
11048 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11049 ret = AXIS_ANCESTOR;
11050 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11051 ret = AXIS_ANCESTOR_OR_SELF;
11052 if (xmlStrEqual(name, BAD_CAST "attribute"))
11053 ret = AXIS_ATTRIBUTE;
11054 break;
11055 case 'c':
11056 if (xmlStrEqual(name, BAD_CAST "child"))
11057 ret = AXIS_CHILD;
11058 break;
11059 case 'd':
11060 if (xmlStrEqual(name, BAD_CAST "descendant"))
11061 ret = AXIS_DESCENDANT;
11062 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11063 ret = AXIS_DESCENDANT_OR_SELF;
11064 break;
11065 case 'f':
11066 if (xmlStrEqual(name, BAD_CAST "following"))
11067 ret = AXIS_FOLLOWING;
11068 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11069 ret = AXIS_FOLLOWING_SIBLING;
11070 break;
11071 case 'n':
11072 if (xmlStrEqual(name, BAD_CAST "namespace"))
11073 ret = AXIS_NAMESPACE;
11074 break;
11075 case 'p':
11076 if (xmlStrEqual(name, BAD_CAST "parent"))
11077 ret = AXIS_PARENT;
11078 if (xmlStrEqual(name, BAD_CAST "preceding"))
11079 ret = AXIS_PRECEDING;
11080 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11081 ret = AXIS_PRECEDING_SIBLING;
11082 break;
11083 case 's':
11084 if (xmlStrEqual(name, BAD_CAST "self"))
11085 ret = AXIS_SELF;
11086 break;
11087 }
11088 return(ret);
11089}
11090
11091/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011092 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +000011093 * @ctxt: the XPath Parser context
11094 *
11095 * [4] Step ::= AxisSpecifier NodeTest Predicate*
11096 * | AbbreviatedStep
11097 *
11098 * [12] AbbreviatedStep ::= '.' | '..'
11099 *
11100 * [5] AxisSpecifier ::= AxisName '::'
11101 * | AbbreviatedAxisSpecifier
11102 *
11103 * [13] AbbreviatedAxisSpecifier ::= '@'?
11104 *
11105 * Modified for XPtr range support as:
11106 *
11107 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11108 * | AbbreviatedStep
11109 * | 'range-to' '(' Expr ')' Predicate*
11110 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011111 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +000011112 * A location step of . is short for self::node(). This is
11113 * particularly useful in conjunction with //. For example, the
11114 * location path .//para is short for
11115 * self::node()/descendant-or-self::node()/child::para
11116 * and so will select all para descendant elements of the context
11117 * node.
11118 * Similarly, a location step of .. is short for parent::node().
11119 * For example, ../title is short for parent::node()/child::title
11120 * and so will select the title children of the parent of the context
11121 * node.
11122 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011123static void
11124xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011125#ifdef LIBXML_XPTR_ENABLED
11126 int rangeto = 0;
11127 int op2 = -1;
11128#endif
11129
Owen Taylor3473f882001-02-23 17:55:21 +000011130 SKIP_BLANKS;
11131 if ((CUR == '.') && (NXT(1) == '.')) {
11132 SKIP(2);
11133 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011134 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11135 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011136 } else if (CUR == '.') {
11137 NEXT;
11138 SKIP_BLANKS;
11139 } else {
11140 xmlChar *name = NULL;
11141 const xmlChar *prefix = NULL;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011142 xmlXPathTestVal test = (xmlXPathTestVal) 0;
William M. Brack78637da2003-07-31 14:47:38 +000011143 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011144 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011145 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +000011146
11147 /*
11148 * The modification needed for XPointer change to the production
11149 */
11150#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011151 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +000011152 name = xmlXPathParseNCName(ctxt);
11153 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011154 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011155 xmlFree(name);
11156 SKIP_BLANKS;
11157 if (CUR != '(') {
11158 XP_ERROR(XPATH_EXPR_ERROR);
11159 }
11160 NEXT;
11161 SKIP_BLANKS;
11162
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011163 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011164 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +000011165 CHECK_ERROR;
11166
11167 SKIP_BLANKS;
11168 if (CUR != ')') {
11169 XP_ERROR(XPATH_EXPR_ERROR);
11170 }
11171 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011172 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000011173 goto eval_predicates;
11174 }
11175 }
11176#endif
Daniel Veillard2156a562001-04-28 12:24:34 +000011177 if (CUR == '*') {
11178 axis = AXIS_CHILD;
11179 } else {
11180 if (name == NULL)
11181 name = xmlXPathParseNCName(ctxt);
11182 if (name != NULL) {
11183 axis = xmlXPathIsAxisName(name);
11184 if (axis != 0) {
11185 SKIP_BLANKS;
11186 if ((CUR == ':') && (NXT(1) == ':')) {
11187 SKIP(2);
11188 xmlFree(name);
11189 name = NULL;
11190 } else {
11191 /* an element name can conflict with an axis one :-\ */
11192 axis = AXIS_CHILD;
11193 }
Owen Taylor3473f882001-02-23 17:55:21 +000011194 } else {
Owen Taylor3473f882001-02-23 17:55:21 +000011195 axis = AXIS_CHILD;
11196 }
Daniel Veillard2156a562001-04-28 12:24:34 +000011197 } else if (CUR == '@') {
11198 NEXT;
11199 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +000011200 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +000011201 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +000011202 }
Owen Taylor3473f882001-02-23 17:55:21 +000011203 }
11204
11205 CHECK_ERROR;
11206
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011207 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +000011208 if (test == 0)
11209 return;
11210
Daniel Veillarded6c5492005-07-23 15:00:22 +000011211 if ((prefix != NULL) && (ctxt->context != NULL) &&
11212 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11213 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11214 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11215 }
11216 }
Owen Taylor3473f882001-02-23 17:55:21 +000011217#ifdef DEBUG_STEP
11218 xmlGenericError(xmlGenericErrorContext,
11219 "Basis : computing new set\n");
11220#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011221
Owen Taylor3473f882001-02-23 17:55:21 +000011222#ifdef DEBUG_STEP
11223 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011224 if (ctxt->value == NULL)
11225 xmlGenericError(xmlGenericErrorContext, "no value\n");
11226 else if (ctxt->value->nodesetval == NULL)
11227 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11228 else
11229 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011230#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011231
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011232#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +000011233eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011234#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011235 op1 = ctxt->comp->last;
11236 ctxt->comp->last = -1;
11237
Owen Taylor3473f882001-02-23 17:55:21 +000011238 SKIP_BLANKS;
11239 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011240 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011241 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011242
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011243#ifdef LIBXML_XPTR_ENABLED
11244 if (rangeto) {
11245 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11246 } else
11247#endif
11248 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11249 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011250
Owen Taylor3473f882001-02-23 17:55:21 +000011251 }
11252#ifdef DEBUG_STEP
11253 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011254 if (ctxt->value == NULL)
11255 xmlGenericError(xmlGenericErrorContext, "no value\n");
11256 else if (ctxt->value->nodesetval == NULL)
11257 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11258 else
11259 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11260 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011261#endif
11262}
11263
11264/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011265 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011266 * @ctxt: the XPath Parser context
11267 *
11268 * [3] RelativeLocationPath ::= Step
11269 * | RelativeLocationPath '/' Step
11270 * | AbbreviatedRelativeLocationPath
11271 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
11272 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011273 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +000011274 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011275static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011276xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011277(xmlXPathParserContextPtr ctxt) {
11278 SKIP_BLANKS;
11279 if ((CUR == '/') && (NXT(1) == '/')) {
11280 SKIP(2);
11281 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011282 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11283 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011284 } else if (CUR == '/') {
11285 NEXT;
11286 SKIP_BLANKS;
11287 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011288 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011289 SKIP_BLANKS;
11290 while (CUR == '/') {
11291 if ((CUR == '/') && (NXT(1) == '/')) {
11292 SKIP(2);
11293 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011294 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +000011295 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011296 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011297 } else if (CUR == '/') {
11298 NEXT;
11299 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011300 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011301 }
11302 SKIP_BLANKS;
11303 }
11304}
11305
11306/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011307 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011308 * @ctxt: the XPath Parser context
11309 *
11310 * [1] LocationPath ::= RelativeLocationPath
11311 * | AbsoluteLocationPath
11312 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
11313 * | AbbreviatedAbsoluteLocationPath
11314 * [10] AbbreviatedAbsoluteLocationPath ::=
11315 * '//' RelativeLocationPath
11316 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011317 * Compile a location path
11318 *
Owen Taylor3473f882001-02-23 17:55:21 +000011319 * // is short for /descendant-or-self::node()/. For example,
11320 * //para is short for /descendant-or-self::node()/child::para and
11321 * so will select any para element in the document (even a para element
11322 * that is a document element will be selected by //para since the
11323 * document element node is a child of the root node); div//para is
11324 * short for div/descendant-or-self::node()/child::para and so will
11325 * select all para descendants of div children.
11326 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011327static void
11328xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000011329 SKIP_BLANKS;
11330 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011331 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011332 } else {
11333 while (CUR == '/') {
11334 if ((CUR == '/') && (NXT(1) == '/')) {
11335 SKIP(2);
11336 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011337 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11338 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011339 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011340 } else if (CUR == '/') {
11341 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +000011342 SKIP_BLANKS;
11343 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +000011344 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +000011345 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011346 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011347 }
11348 }
11349 }
11350}
11351
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011352/************************************************************************
11353 * *
11354 * XPath precompiled expression evaluation *
11355 * *
11356 ************************************************************************/
11357
Daniel Veillardf06307e2001-07-03 10:35:50 +000011358static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011359xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11360
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011361#ifdef DEBUG_STEP
11362static void
11363xmlXPathDebugDumpStepAxis(xmlXPathAxisVal axis,
11364 xmlXPathTestVal test,
11365 int nbNodes)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011366{
Daniel Veillardf06307e2001-07-03 10:35:50 +000011367 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011368 switch (axis) {
11369 case AXIS_ANCESTOR:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011370 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011371 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011372 case AXIS_ANCESTOR_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011373 xmlGenericError(xmlGenericErrorContext,
11374 "axis 'ancestors-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011375 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011376 case AXIS_ATTRIBUTE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011377 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011378 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011379 case AXIS_CHILD:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011380 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011381 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011382 case AXIS_DESCENDANT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011383 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011384 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011385 case AXIS_DESCENDANT_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011386 xmlGenericError(xmlGenericErrorContext,
11387 "axis 'descendant-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011388 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011389 case AXIS_FOLLOWING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011390 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011391 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011392 case AXIS_FOLLOWING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011393 xmlGenericError(xmlGenericErrorContext,
11394 "axis 'following-siblings' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011395 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011396 case AXIS_NAMESPACE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011397 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011398 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011399 case AXIS_PARENT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011400 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011401 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011402 case AXIS_PRECEDING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011403 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011404 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011405 case AXIS_PRECEDING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011406 xmlGenericError(xmlGenericErrorContext,
11407 "axis 'preceding-sibling' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011408 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011409 case AXIS_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011410 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011411 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011412 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011413 xmlGenericError(xmlGenericErrorContext,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011414 " context contains %d nodes\n", nbNodes);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011415 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011416 case NODE_TEST_NONE:
11417 xmlGenericError(xmlGenericErrorContext,
11418 " searching for none !!!\n");
11419 break;
11420 case NODE_TEST_TYPE:
11421 xmlGenericError(xmlGenericErrorContext,
11422 " searching for type %d\n", type);
11423 break;
11424 case NODE_TEST_PI:
11425 xmlGenericError(xmlGenericErrorContext,
11426 " searching for PI !!!\n");
11427 break;
11428 case NODE_TEST_ALL:
11429 xmlGenericError(xmlGenericErrorContext,
11430 " searching for *\n");
11431 break;
11432 case NODE_TEST_NS:
11433 xmlGenericError(xmlGenericErrorContext,
11434 " searching for namespace %s\n",
11435 prefix);
11436 break;
11437 case NODE_TEST_NAME:
11438 xmlGenericError(xmlGenericErrorContext,
11439 " searching for name %s\n", name);
11440 if (prefix != NULL)
11441 xmlGenericError(xmlGenericErrorContext,
11442 " with namespace %s\n", prefix);
11443 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011444 }
11445 xmlGenericError(xmlGenericErrorContext, "Testing : ");
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011446}
11447#endif /* DEBUG_STEP */
11448
11449static int
11450xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11451 xmlXPathStepOpPtr op,
11452 xmlNodeSetPtr set,
11453 int contextSize,
11454 int hasNsNodes)
11455{
11456 if (op->ch1 != -1) {
11457 xmlXPathCompExprPtr comp = ctxt->comp;
11458 /*
11459 * Process inner predicates first.
11460 */
11461 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11462 /*
11463 * TODO: raise an internal error.
11464 */
11465 }
11466 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11467 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11468 CHECK_ERROR0;
11469 if (contextSize <= 0)
11470 return(0);
11471 }
11472 if (op->ch2 != -1) {
11473 xmlXPathContextPtr xpctxt = ctxt->context;
11474 xmlNodePtr contextNode, oldContextNode;
11475 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011476 int i, res, contextPos = 0, newContextSize;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011477 xmlXPathStepOpPtr exprOp;
11478 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11479
11480#ifdef LIBXML_XPTR_ENABLED
11481 /*
11482 * URGENT TODO: Check the following:
11483 * We don't expect location sets if evaluating prediates, right?
11484 * Only filters should expect location sets, right?
11485 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011486#endif
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011487 /*
11488 * SPEC XPath 1.0:
11489 * "For each node in the node-set to be filtered, the
11490 * PredicateExpr is evaluated with that node as the
11491 * context node, with the number of nodes in the
11492 * node-set as the context size, and with the proximity
11493 * position of the node in the node-set with respect to
11494 * the axis as the context position;"
11495 * @oldset is the node-set" to be filtered.
11496 *
11497 * SPEC XPath 1.0:
11498 * "only predicates change the context position and
11499 * context size (see [2.4 Predicates])."
11500 * Example:
11501 * node-set context pos
11502 * nA 1
11503 * nB 2
11504 * nC 3
11505 * After applying predicate [position() > 1] :
11506 * node-set context pos
11507 * nB 1
11508 * nC 2
11509 */
11510 oldContextNode = xpctxt->node;
11511 oldContextDoc = xpctxt->doc;
11512 /*
11513 * Get the expression of this predicate.
11514 */
11515 exprOp = &ctxt->comp->steps[op->ch2];
11516 newContextSize = 0;
11517 for (i = 0; i < set->nodeNr; i++) {
11518 if (set->nodeTab[i] == NULL)
11519 continue;
11520
11521 contextNode = set->nodeTab[i];
11522 xpctxt->node = contextNode;
11523 xpctxt->contextSize = contextSize;
11524 xpctxt->proximityPosition = ++contextPos;
11525
11526 /*
11527 * Also set the xpath document in case things like
11528 * key() are evaluated in the predicate.
11529 */
11530 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11531 (contextNode->doc != NULL))
11532 xpctxt->doc = contextNode->doc;
11533 /*
11534 * Evaluate the predicate expression with 1 context node
11535 * at a time; this node is packaged into a node set; this
11536 * node set is handed over to the evaluation mechanism.
11537 */
11538 if (contextObj == NULL)
11539 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11540 else
11541 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11542 contextNode);
11543
11544 valuePush(ctxt, contextObj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011545
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011546 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011547
11548 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1))
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011549 goto evaluation_error;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011550
11551 if (res != 0) {
11552 newContextSize++;
11553 } else {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011554 /*
11555 * Remove the entry from the initial node set.
11556 */
11557 set->nodeTab[i] = NULL;
11558 if (contextNode->type == XML_NAMESPACE_DECL)
11559 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011560 }
11561 if (ctxt->value == contextObj) {
11562 /*
11563 * Don't free the temporary XPath object holding the
11564 * context node, in order to avoid massive recreation
11565 * inside this loop.
11566 */
11567 valuePop(ctxt);
11568 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11569 } else {
11570 /*
11571 * TODO: The object was lost in the evaluation machinery.
11572 * Can this happen? Maybe in internal-error cases.
11573 */
11574 contextObj = NULL;
11575 }
11576 }
11577 goto evaluation_exit;
11578
11579evaluation_error:
11580 xmlXPathNodeSetClear(set, hasNsNodes);
11581 newContextSize = 0;
11582
11583evaluation_exit:
11584 if (contextObj != NULL) {
11585 if (ctxt->value == contextObj)
11586 valuePop(ctxt);
11587 xmlXPathReleaseObject(xpctxt, contextObj);
11588 }
11589 if (exprRes != NULL)
11590 xmlXPathReleaseObject(ctxt->context, exprRes);
11591 /*
11592 * Reset/invalidate the context.
11593 */
11594 xpctxt->node = oldContextNode;
11595 xpctxt->doc = oldContextDoc;
11596 xpctxt->contextSize = -1;
11597 xpctxt->proximityPosition = -1;
11598 return(newContextSize);
11599 }
11600 return(contextSize);
11601}
11602
11603static int
11604xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11605 xmlXPathStepOpPtr op,
11606 xmlNodeSetPtr set,
11607 int contextSize,
11608 int minPos,
11609 int maxPos,
11610 int hasNsNodes)
11611{
11612 if (op->ch1 != -1) {
11613 xmlXPathCompExprPtr comp = ctxt->comp;
11614 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11615 /*
11616 * TODO: raise an internal error.
11617 */
11618 }
11619 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11620 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11621 CHECK_ERROR0;
11622 if (contextSize <= 0)
11623 return(0);
11624 }
11625 /*
11626 * Check if the node set contains a sufficient number of nodes for
11627 * the requested range.
11628 */
11629 if (contextSize < minPos) {
11630 xmlXPathNodeSetClear(set, hasNsNodes);
11631 return(0);
11632 }
11633 if (op->ch2 == -1) {
11634 /*
11635 * TODO: Can this ever happen?
11636 */
11637 return (contextSize);
11638 } else {
11639 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011640 int i, pos = 0, newContextSize = 0, contextPos = 0, res;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011641 xmlXPathStepOpPtr exprOp;
11642 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11643 xmlNodePtr oldContextNode, contextNode = NULL;
11644 xmlXPathContextPtr xpctxt = ctxt->context;
11645
11646#ifdef LIBXML_XPTR_ENABLED
11647 /*
11648 * URGENT TODO: Check the following:
11649 * We don't expect location sets if evaluating prediates, right?
11650 * Only filters should expect location sets, right?
11651 */
11652#endif /* LIBXML_XPTR_ENABLED */
11653
11654 /*
11655 * Save old context.
11656 */
11657 oldContextNode = xpctxt->node;
11658 oldContextDoc = xpctxt->doc;
11659 /*
11660 * Get the expression of this predicate.
11661 */
11662 exprOp = &ctxt->comp->steps[op->ch2];
11663 for (i = 0; i < set->nodeNr; i++) {
11664 if (set->nodeTab[i] == NULL)
11665 continue;
11666
11667 contextNode = set->nodeTab[i];
11668 xpctxt->node = contextNode;
11669 xpctxt->contextSize = contextSize;
11670 xpctxt->proximityPosition = ++contextPos;
11671
11672 /*
11673 * Initialize the new set.
11674 * Also set the xpath document in case things like
11675 * key() evaluation are attempted on the predicate
11676 */
11677 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11678 (contextNode->doc != NULL))
11679 xpctxt->doc = contextNode->doc;
11680 /*
11681 * Evaluate the predicate expression with 1 context node
11682 * at a time; this node is packaged into a node set; this
11683 * node set is handed over to the evaluation mechanism.
11684 */
11685 if (contextObj == NULL)
11686 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11687 else
11688 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11689 contextNode);
11690
11691 valuePush(ctxt, contextObj);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011692 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011693
11694 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1))
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011695 goto evaluation_error;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011696
11697 if (res)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011698 pos++;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011699
11700 if (res && (pos >= minPos) && (pos <= maxPos)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011701 /*
11702 * Fits in the requested range.
11703 */
11704 newContextSize++;
11705 if (minPos == maxPos) {
11706 /*
11707 * Only 1 node was requested.
11708 */
11709 if (contextNode->type == XML_NAMESPACE_DECL) {
11710 /*
11711 * As always: take care of those nasty
11712 * namespace nodes.
11713 */
11714 set->nodeTab[i] = NULL;
11715 }
11716 xmlXPathNodeSetClear(set, hasNsNodes);
11717 set->nodeNr = 1;
11718 set->nodeTab[0] = contextNode;
11719 goto evaluation_exit;
11720 }
11721 if (pos == maxPos) {
11722 /*
11723 * We are done.
11724 */
11725 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11726 goto evaluation_exit;
11727 }
11728 } else {
11729 /*
11730 * Remove the entry from the initial node set.
11731 */
11732 set->nodeTab[i] = NULL;
11733 if (contextNode->type == XML_NAMESPACE_DECL)
11734 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11735 }
11736 if (exprRes != NULL) {
11737 xmlXPathReleaseObject(ctxt->context, exprRes);
11738 exprRes = NULL;
11739 }
11740 if (ctxt->value == contextObj) {
11741 /*
11742 * Don't free the temporary XPath object holding the
11743 * context node, in order to avoid massive recreation
11744 * inside this loop.
11745 */
11746 valuePop(ctxt);
11747 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11748 } else {
11749 /*
11750 * The object was lost in the evaluation machinery.
11751 * Can this happen? Maybe in case of internal-errors.
11752 */
11753 contextObj = NULL;
11754 }
11755 }
11756 goto evaluation_exit;
11757
11758evaluation_error:
11759 xmlXPathNodeSetClear(set, hasNsNodes);
11760 newContextSize = 0;
11761
11762evaluation_exit:
11763 if (contextObj != NULL) {
11764 if (ctxt->value == contextObj)
11765 valuePop(ctxt);
11766 xmlXPathReleaseObject(xpctxt, contextObj);
11767 }
11768 if (exprRes != NULL)
11769 xmlXPathReleaseObject(ctxt->context, exprRes);
11770 /*
11771 * Reset/invalidate the context.
11772 */
11773 xpctxt->node = oldContextNode;
11774 xpctxt->doc = oldContextDoc;
11775 xpctxt->contextSize = -1;
11776 xpctxt->proximityPosition = -1;
11777 return(newContextSize);
11778 }
11779 return(contextSize);
11780}
11781
11782static int
11783xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11784 xmlXPathStepOpPtr op,
11785 int *maxPos)
11786{
11787
11788 xmlXPathStepOpPtr exprOp;
11789
11790 /*
11791 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11792 */
11793
11794 /*
11795 * If not -1, then ch1 will point to:
11796 * 1) For predicates (XPATH_OP_PREDICATE):
11797 * - an inner predicate operator
11798 * 2) For filters (XPATH_OP_FILTER):
11799 * - an inner filter operater OR
11800 * - an expression selecting the node set.
11801 * E.g. "key('a', 'b')" or "(//foo | //bar)".
11802 */
11803 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11804 return(0);
11805
11806 if (op->ch2 != -1) {
11807 exprOp = &ctxt->comp->steps[op->ch2];
11808 } else
11809 return(0);
11810
11811 if ((exprOp != NULL) &&
11812 (exprOp->op == XPATH_OP_VALUE) &&
11813 (exprOp->value4 != NULL) &&
11814 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11815 {
11816 /*
11817 * We have a "[n]" predicate here.
11818 * TODO: Unfortunately this simplistic test here is not
11819 * able to detect a position() predicate in compound
11820 * expressions like "[@attr = 'a" and position() = 1],
11821 * and even not the usage of position() in
11822 * "[position() = 1]"; thus - obviously - a position-range,
11823 * like it "[position() < 5]", is also not detected.
11824 * Maybe we could rewrite the AST to ease the optimization.
11825 */
11826 *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11827
11828 if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
11829 (float) *maxPos)
11830 {
11831 return(1);
11832 }
11833 }
11834 return(0);
11835}
11836
11837static int
11838xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11839 xmlXPathStepOpPtr op,
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011840 xmlNodePtr * first, xmlNodePtr * last,
11841 int toBool)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011842{
11843
11844#define XP_TEST_HIT \
11845 if (hasAxisRange != 0) { \
11846 if (++pos == maxPos) { \
11847 addNode(seq, cur); \
11848 goto axis_range_end; } \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011849 } else { \
11850 addNode(seq, cur); \
11851 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011852
11853#define XP_TEST_HIT_NS \
11854 if (hasAxisRange != 0) { \
11855 if (++pos == maxPos) { \
11856 hasNsNodes = 1; \
11857 xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
11858 goto axis_range_end; } \
11859 } else { \
11860 hasNsNodes = 1; \
11861 xmlXPathNodeSetAddNs(seq, \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011862 xpctxt->node, (xmlNsPtr) cur); \
11863 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011864
11865 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11866 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11867 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11868 const xmlChar *prefix = op->value4;
11869 const xmlChar *name = op->value5;
11870 const xmlChar *URI = NULL;
11871
11872#ifdef DEBUG_STEP
11873 int nbMatches = 0, prevMatches = 0;
11874#endif
11875 int total = 0, hasNsNodes = 0;
11876 /* The popped object holding the context nodes */
11877 xmlXPathObjectPtr obj;
11878 /* The set of context nodes for the node tests */
11879 xmlNodeSetPtr contextSeq;
11880 int contextIdx;
11881 xmlNodePtr contextNode;
11882 /* The context node for a compound traversal */
11883 xmlNodePtr outerContextNode;
11884 /* The final resulting node set wrt to all context nodes */
11885 xmlNodeSetPtr outSeq;
11886 /*
11887 * The temporary resulting node set wrt 1 context node.
11888 * Used to feed predicate evaluation.
11889 */
11890 xmlNodeSetPtr seq;
11891 xmlNodePtr cur;
11892 /* First predicate operator */
11893 xmlXPathStepOpPtr predOp;
11894 int maxPos; /* The requested position() (when a "[n]" predicate) */
11895 int hasPredicateRange, hasAxisRange, pos, size, newSize;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011896 int breakOnFirstHit;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011897
11898 xmlXPathTraversalFunction next = NULL;
11899 /* compound axis traversal */
11900 xmlXPathTraversalFunctionExt outerNext = NULL;
11901 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
11902 xmlXPathNodeSetMergeFunction mergeAndClear;
11903 xmlNodePtr oldContextNode;
11904 xmlXPathContextPtr xpctxt = ctxt->context;
11905
11906
11907 CHECK_TYPE0(XPATH_NODESET);
11908 obj = valuePop(ctxt);
11909 /*
11910 * Setup namespaces.
11911 */
11912 if (prefix != NULL) {
11913 URI = xmlXPathNsLookup(xpctxt, prefix);
11914 if (URI == NULL) {
11915 xmlXPathReleaseObject(xpctxt, obj);
11916 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11917 }
11918 }
11919 /*
11920 * Setup axis.
11921 *
11922 * MAYBE FUTURE TODO: merging optimizations:
11923 * - If the nodes to be traversed wrt to the initial nodes and
11924 * the current axis cannot overlap, then we could avoid searching
11925 * for duplicates during the merge.
11926 * But the question is how/when to evaluate if they cannot overlap.
11927 * Example: if we know that for two initial nodes, the one is
11928 * not in the ancestor-or-self axis of the other, then we could safely
11929 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
11930 * the descendant-or-self axis.
11931 */
11932 addNode = xmlXPathNodeSetAdd;
11933 mergeAndClear = xmlXPathNodeSetMergeAndClear;
11934 switch (axis) {
11935 case AXIS_ANCESTOR:
11936 first = NULL;
11937 next = xmlXPathNextAncestor;
11938 break;
11939 case AXIS_ANCESTOR_OR_SELF:
11940 first = NULL;
11941 next = xmlXPathNextAncestorOrSelf;
11942 break;
11943 case AXIS_ATTRIBUTE:
11944 first = NULL;
11945 last = NULL;
11946 next = xmlXPathNextAttribute;
11947 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11948 break;
11949 case AXIS_CHILD:
11950 last = NULL;
11951 if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
11952 /*
11953 * This iterator will give us only nodes which can
11954 * hold element nodes.
11955 */
11956 outerNext = xmlXPathNextDescendantOrSelfElemParent;
11957 }
11958 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
11959 (type == NODE_TYPE_NODE))
11960 {
11961 /*
11962 * Optimization if an element node type is 'element'.
11963 */
11964 next = xmlXPathNextChildElement;
11965 } else
11966 next = xmlXPathNextChild;
11967 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11968 break;
11969 case AXIS_DESCENDANT:
11970 last = NULL;
11971 next = xmlXPathNextDescendant;
11972 break;
11973 case AXIS_DESCENDANT_OR_SELF:
11974 last = NULL;
11975 next = xmlXPathNextDescendantOrSelf;
11976 break;
11977 case AXIS_FOLLOWING:
11978 last = NULL;
11979 next = xmlXPathNextFollowing;
11980 break;
11981 case AXIS_FOLLOWING_SIBLING:
11982 last = NULL;
11983 next = xmlXPathNextFollowingSibling;
11984 break;
11985 case AXIS_NAMESPACE:
11986 first = NULL;
11987 last = NULL;
11988 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
11989 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11990 break;
11991 case AXIS_PARENT:
11992 first = NULL;
11993 next = xmlXPathNextParent;
11994 break;
11995 case AXIS_PRECEDING:
11996 first = NULL;
11997 next = xmlXPathNextPrecedingInternal;
11998 break;
11999 case AXIS_PRECEDING_SIBLING:
12000 first = NULL;
12001 next = xmlXPathNextPrecedingSibling;
12002 break;
12003 case AXIS_SELF:
12004 first = NULL;
12005 last = NULL;
12006 next = xmlXPathNextSelf;
12007 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12008 break;
12009 }
12010
12011#ifdef DEBUG_STEP
12012 xmlXPathDebugDumpStepAxis(axis, test,
12013 (obj->nodesetval != NULL) ? obj->nodsetval->nodeNr : 0);
12014#endif
12015
12016 if (next == NULL) {
12017 xmlXPathReleaseObject(xpctxt, obj);
12018 return(0);
12019 }
12020 contextSeq = obj->nodesetval;
12021 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12022 xmlXPathReleaseObject(xpctxt, obj);
12023 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12024 return(0);
12025 }
12026 /*
12027 * Predicate optimization ---------------------------------------------
12028 * If this step has a last predicate, which contains a position(),
12029 * then we'll optimize (although not exactly "position()", but only
12030 * the short-hand form, i.e., "[n]".
12031 *
12032 * Example - expression "/foo[parent::bar][1]":
12033 *
12034 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12035 * ROOT -- op->ch1
12036 * PREDICATE -- op->ch2 (predOp)
12037 * PREDICATE -- predOp->ch1 = [parent::bar]
12038 * SORT
12039 * COLLECT 'parent' 'name' 'node' bar
12040 * NODE
12041 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12042 *
12043 */
12044 maxPos = 0;
12045 predOp = NULL;
12046 hasPredicateRange = 0;
12047 hasAxisRange = 0;
12048 if (op->ch2 != -1) {
12049 /*
12050 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12051 */
12052 predOp = &ctxt->comp->steps[op->ch2];
12053 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12054 if (predOp->ch1 != -1) {
12055 /*
12056 * Use the next inner predicate operator.
12057 */
12058 predOp = &ctxt->comp->steps[predOp->ch1];
12059 hasPredicateRange = 1;
12060 } else {
12061 /*
12062 * There's no other predicate than the [n] predicate.
12063 */
12064 predOp = NULL;
12065 hasAxisRange = 1;
12066 }
12067 }
12068 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012069 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012070 /*
12071 * Axis traversal -----------------------------------------------------
12072 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012073 /*
12074 * 2.3 Node Tests
12075 * - For the attribute axis, the principal node type is attribute.
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012076 * - For the namespace axis, the principal node type is namespace.
12077 * - For other axes, the principal node type is element.
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012078 *
12079 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012080 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012081 * select all element children of the context node
12082 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012083 oldContextNode = xpctxt->node;
12084 addNode = xmlXPathNodeSetAddUnique;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012085 outSeq = NULL;
12086 seq = NULL;
12087 outerContextNode = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012088 contextNode = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012089 contextIdx = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012090
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012091
12092 while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
12093 if (outerNext != NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012094 /*
12095 * This is a compound traversal.
12096 */
12097 if (contextNode == NULL) {
12098 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012099 * Set the context for the outer traversal.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012100 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012101 outerContextNode = contextSeq->nodeTab[contextIdx++];
12102 contextNode = outerNext(NULL, outerContextNode);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012103 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012104 contextNode = outerNext(contextNode, outerContextNode);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012105 if (contextNode == NULL)
12106 continue;
12107 /*
12108 * Set the context for the main traversal.
12109 */
12110 xpctxt->node = contextNode;
12111 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012112 xpctxt->node = contextSeq->nodeTab[contextIdx++];
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012113
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012114 if (seq == NULL) {
12115 seq = xmlXPathNodeSetCreate(NULL);
12116 if (seq == NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012117 total = 0;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012118 goto error;
12119 }
12120 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012121 /*
12122 * Traverse the axis and test the nodes.
12123 */
12124 pos = 0;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012125 cur = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012126 hasNsNodes = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012127 do {
12128 cur = next(ctxt, cur);
12129 if (cur == NULL)
12130 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012131
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012132 /*
12133 * QUESTION TODO: What does the "first" and "last" stuff do?
12134 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012135 if ((first != NULL) && (*first != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012136 if (*first == cur)
12137 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012138 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012139#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012140 (xmlXPathCmpNodesExt(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012141#else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012142 (xmlXPathCmpNodes(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012143#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012144 {
12145 break;
12146 }
12147 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012148 if ((last != NULL) && (*last != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012149 if (*last == cur)
12150 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012151 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012152#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012153 (xmlXPathCmpNodesExt(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012154#else
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012155 (xmlXPathCmpNodes(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012156#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012157 {
12158 break;
12159 }
12160 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012161
12162 total++;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012163
Daniel Veillardf06307e2001-07-03 10:35:50 +000012164#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012165 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12166#endif
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012167 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012168 case NODE_TEST_NONE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012169 total = 0;
12170 STRANGE
12171 goto error;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012172 case NODE_TEST_TYPE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012173 /*
12174 * TODO: Don't we need to use
12175 * xmlXPathNodeSetAddNs() for namespace nodes here?
12176 * Surprisingly, some c14n tests fail, if we do this.
12177 */
12178 if (type == NODE_TYPE_NODE) {
12179 switch (cur->type) {
12180 case XML_DOCUMENT_NODE:
12181 case XML_HTML_DOCUMENT_NODE:
12182#ifdef LIBXML_DOCB_ENABLED
12183 case XML_DOCB_DOCUMENT_NODE:
12184#endif
12185 case XML_ELEMENT_NODE:
12186 case XML_ATTRIBUTE_NODE:
12187 case XML_PI_NODE:
12188 case XML_COMMENT_NODE:
12189 case XML_CDATA_SECTION_NODE:
12190 case XML_TEXT_NODE:
12191 case XML_NAMESPACE_DECL:
12192 XP_TEST_HIT
12193 break;
12194 default:
12195 break;
12196 }
12197 } else if (cur->type == type) {
12198 XP_TEST_HIT
12199 } else if ((type == NODE_TYPE_TEXT) &&
12200 (cur->type == XML_CDATA_SECTION_NODE))
12201 {
12202 XP_TEST_HIT
12203 }
12204 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012205 case NODE_TEST_PI:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012206 if ((cur->type == XML_PI_NODE) &&
12207 ((name == NULL) || xmlStrEqual(name, cur->name)))
12208 {
12209 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012210 }
12211 break;
12212 case NODE_TEST_ALL:
12213 if (axis == AXIS_ATTRIBUTE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012214 if (cur->type == XML_ATTRIBUTE_NODE)
12215 {
12216 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012217 }
12218 } else if (axis == AXIS_NAMESPACE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012219 if (cur->type == XML_NAMESPACE_DECL)
12220 {
12221 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012222 }
12223 } else {
12224 if (cur->type == XML_ELEMENT_NODE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012225 if (prefix == NULL)
12226 {
12227 XP_TEST_HIT
12228
Daniel Veillardf06307e2001-07-03 10:35:50 +000012229 } else if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012230 (xmlStrEqual(URI, cur->ns->href)))
12231 {
12232 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012233 }
12234 }
12235 }
12236 break;
12237 case NODE_TEST_NS:{
12238 TODO;
12239 break;
12240 }
12241 case NODE_TEST_NAME:
12242 switch (cur->type) {
12243 case XML_ELEMENT_NODE:
12244 if (xmlStrEqual(name, cur->name)) {
12245 if (prefix == NULL) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012246 if (cur->ns == NULL)
12247 {
12248 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012249 }
12250 } else {
12251 if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012252 (xmlStrEqual(URI, cur->ns->href)))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012253 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012254 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012255 }
12256 }
12257 }
12258 break;
12259 case XML_ATTRIBUTE_NODE:{
12260 xmlAttrPtr attr = (xmlAttrPtr) cur;
12261
12262 if (xmlStrEqual(name, attr->name)) {
12263 if (prefix == NULL) {
12264 if ((attr->ns == NULL) ||
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012265 (attr->ns->prefix == NULL))
12266 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012267 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012268 }
12269 } else {
12270 if ((attr->ns != NULL) &&
12271 (xmlStrEqual(URI,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012272 attr->ns->href)))
12273 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012274 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012275 }
12276 }
12277 }
12278 break;
12279 }
12280 case XML_NAMESPACE_DECL:
12281 if (cur->type == XML_NAMESPACE_DECL) {
12282 xmlNsPtr ns = (xmlNsPtr) cur;
12283
12284 if ((ns->prefix != NULL) && (name != NULL)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012285 && (xmlStrEqual(ns->prefix, name)))
12286 {
12287 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012288 }
12289 }
12290 break;
12291 default:
12292 break;
12293 }
12294 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012295 } /* switch(test) */
12296 } while (cur != NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012297
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012298 goto apply_predicates;
12299
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012300axis_range_end: /* ----------------------------------------------------- */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012301 /*
12302 * We have a "/foo[n]", and position() = n was reached.
12303 * Note that we can have as well "/foo/::parent::foo[1]", so
12304 * a duplicate-aware merge is still needed.
12305 * Merge with the result.
12306 */
12307 if (outSeq == NULL) {
12308 outSeq = seq;
12309 seq = NULL;
12310 } else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012311 outSeq = mergeAndClear(outSeq, seq, 0);
12312 /*
12313 * Break if only a true/false result was requested.
12314 */
12315 if (toBool)
12316 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012317 continue;
12318
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012319first_hit: /* ---------------------------------------------------------- */
12320 /*
12321 * Break if only a true/false result was requested and
12322 * no predicates existed and a node test succeeded.
12323 */
12324 if (outSeq == NULL) {
12325 outSeq = seq;
12326 seq = NULL;
12327 } else
12328 outSeq = mergeAndClear(outSeq, seq, 0);
12329 break;
12330
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012331#ifdef DEBUG_STEP
12332 if (seq != NULL)
12333 nbMatches += seq->nodeNr;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012334#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012335
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012336apply_predicates: /* --------------------------------------------------- */
12337 /*
12338 * Apply predicates.
12339 */
12340 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12341 /*
12342 * E.g. when we have a "/foo[some expression][n]".
12343 */
12344 /*
12345 * QUESTION TODO: The old predicate evaluation took into
12346 * account location-sets.
12347 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12348 * Do we expect such a set here?
12349 * All what I learned now from the evaluation semantics
12350 * does not indicate that a location-set will be processed
12351 * here, so this looks OK.
12352 */
12353 /*
12354 * Iterate over all predicates, starting with the outermost
12355 * predicate.
12356 * TODO: Problem: we cannot execute the inner predicates first
12357 * since we cannot go back *up* the operator tree!
12358 * Options we have:
12359 * 1) Use of recursive functions (like is it currently done
12360 * via xmlXPathCompOpEval())
12361 * 2) Add a predicate evaluation information stack to the
12362 * context struct
12363 * 3) Change the way the operators are linked; we need a
12364 * "parent" field on xmlXPathStepOp
12365 *
12366 * For the moment, I'll try to solve this with a recursive
12367 * function: xmlXPathCompOpEvalPredicate().
12368 */
12369 size = seq->nodeNr;
12370 if (hasPredicateRange != 0)
12371 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12372 predOp, seq, size, maxPos, maxPos, hasNsNodes);
12373 else
12374 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12375 predOp, seq, size, hasNsNodes);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012376
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012377 if (ctxt->error != XPATH_EXPRESSION_OK) {
12378 total = 0;
12379 goto error;
12380 }
12381 /*
12382 * Add the filtered set of nodes to the result node set.
12383 */
12384 if (newSize == 0) {
12385 /*
12386 * The predicates filtered all nodes out.
12387 */
12388 xmlXPathNodeSetClear(seq, hasNsNodes);
12389 } else if (seq->nodeNr > 0) {
12390 /*
12391 * Add to result set.
12392 */
12393 if (outSeq == NULL) {
12394 if (size != newSize) {
12395 /*
12396 * We need to merge and clear here, since
12397 * the sequence will contained NULLed entries.
12398 */
12399 outSeq = mergeAndClear(NULL, seq, 1);
12400 } else {
12401 outSeq = seq;
12402 seq = NULL;
12403 }
12404 } else
12405 outSeq = mergeAndClear(outSeq, seq,
12406 (size != newSize) ? 1: 0);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012407 /*
12408 * Break if only a true/false result was requested.
12409 */
12410 if (toBool)
12411 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012412 }
12413 } else if (seq->nodeNr > 0) {
12414 /*
12415 * Add to result set.
12416 */
12417 if (outSeq == NULL) {
12418 outSeq = seq;
12419 seq = NULL;
12420 } else {
12421 outSeq = mergeAndClear(outSeq, seq, 0);
12422 }
12423 }
12424 }
12425
12426error:
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012427 if ((obj->boolval) && (obj->user != NULL)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012428 /*
12429 * QUESTION TODO: What does this do and why?
12430 * TODO: Do we have to do this also for the "error"
12431 * cleanup further down?
12432 */
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012433 ctxt->value->boolval = 1;
12434 ctxt->value->user = obj->user;
12435 obj->user = NULL;
12436 obj->boolval = 0;
12437 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012438 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012439
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012440 /*
12441 * Ensure we return at least an emtpy set.
12442 */
12443 if (outSeq == NULL) {
12444 if ((seq != NULL) && (seq->nodeNr == 0))
12445 outSeq = seq;
12446 else
12447 outSeq = xmlXPathNodeSetCreate(NULL);
12448 }
12449 if ((seq != NULL) && (seq != outSeq)) {
12450 xmlXPathFreeNodeSet(seq);
12451 }
12452 /*
12453 * Hand over the result. Better to push the set also in
12454 * case of errors.
12455 */
12456 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12457 /*
12458 * Reset the context node.
12459 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012460 xpctxt->node = oldContextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012461
12462#ifdef DEBUG_STEP
12463 xmlGenericError(xmlGenericErrorContext,
12464 "\nExamined %d nodes, found %d nodes at that step\n",
12465 total, nbMatches);
12466#endif
12467
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012468 return(total);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012469}
12470
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012471static int
12472xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12473 xmlXPathStepOpPtr op, xmlNodePtr * first);
12474
Daniel Veillardf06307e2001-07-03 10:35:50 +000012475/**
12476 * xmlXPathCompOpEvalFirst:
12477 * @ctxt: the XPath parser context with the compiled expression
12478 * @op: an XPath compiled operation
12479 * @first: the first elem found so far
12480 *
12481 * Evaluate the Precompiled XPath operation searching only the first
12482 * element in document order
12483 *
12484 * Returns the number of examined objects.
12485 */
12486static int
12487xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12488 xmlXPathStepOpPtr op, xmlNodePtr * first)
12489{
12490 int total = 0, cur;
12491 xmlXPathCompExprPtr comp;
12492 xmlXPathObjectPtr arg1, arg2;
12493
Daniel Veillard556c6682001-10-06 09:59:51 +000012494 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012495 comp = ctxt->comp;
12496 switch (op->op) {
12497 case XPATH_OP_END:
12498 return (0);
12499 case XPATH_OP_UNION:
12500 total =
12501 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12502 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012503 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012504 if ((ctxt->value != NULL)
12505 && (ctxt->value->type == XPATH_NODESET)
12506 && (ctxt->value->nodesetval != NULL)
12507 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12508 /*
12509 * limit tree traversing to first node in the result
12510 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012511 /*
12512 * OPTIMIZE TODO: This implicitely sorts
12513 * the result, even if not needed. E.g. if the argument
12514 * of the count() function, no sorting is needed.
12515 * OPTIMIZE TODO: How do we know if the node-list wasn't
12516 * aready sorted?
12517 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012518 if (ctxt->value->nodesetval->nodeNr > 1)
12519 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012520 *first = ctxt->value->nodesetval->nodeTab[0];
12521 }
12522 cur =
12523 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12524 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012525 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012526 CHECK_TYPE0(XPATH_NODESET);
12527 arg2 = valuePop(ctxt);
12528
12529 CHECK_TYPE0(XPATH_NODESET);
12530 arg1 = valuePop(ctxt);
12531
12532 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12533 arg2->nodesetval);
12534 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012535 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012536 /* optimizer */
12537 if (total > cur)
12538 xmlXPathCompSwap(op);
12539 return (total + cur);
12540 case XPATH_OP_ROOT:
12541 xmlXPathRoot(ctxt);
12542 return (0);
12543 case XPATH_OP_NODE:
12544 if (op->ch1 != -1)
12545 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012546 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012547 if (op->ch2 != -1)
12548 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012549 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012550 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12551 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012552 return (total);
12553 case XPATH_OP_RESET:
12554 if (op->ch1 != -1)
12555 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012556 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012557 if (op->ch2 != -1)
12558 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012559 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012560 ctxt->context->node = NULL;
12561 return (total);
12562 case XPATH_OP_COLLECT:{
12563 if (op->ch1 == -1)
12564 return (total);
12565
12566 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012567 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012568
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012569 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012570 return (total);
12571 }
12572 case XPATH_OP_VALUE:
12573 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012574 xmlXPathCacheObjectCopy(ctxt->context,
12575 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012576 return (0);
12577 case XPATH_OP_SORT:
12578 if (op->ch1 != -1)
12579 total +=
12580 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12581 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012582 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012583 if ((ctxt->value != NULL)
12584 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012585 && (ctxt->value->nodesetval != NULL)
12586 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012587 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12588 return (total);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012589#ifdef XP_OPTIMIZED_FILTER_FIRST
12590 case XPATH_OP_FILTER:
12591 total =+ xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12592 return (total);
12593#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000012594 default:
12595 return (xmlXPathCompOpEval(ctxt, op));
12596 }
12597}
12598
12599/**
12600 * xmlXPathCompOpEvalLast:
12601 * @ctxt: the XPath parser context with the compiled expression
12602 * @op: an XPath compiled operation
12603 * @last: the last elem found so far
12604 *
12605 * Evaluate the Precompiled XPath operation searching only the last
12606 * element in document order
12607 *
William M. Brack08171912003-12-29 02:52:11 +000012608 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000012609 */
12610static int
12611xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12612 xmlNodePtr * last)
12613{
12614 int total = 0, cur;
12615 xmlXPathCompExprPtr comp;
12616 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +000012617 xmlNodePtr bak;
12618 xmlDocPtr bakd;
12619 int pp;
12620 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012621
Daniel Veillard556c6682001-10-06 09:59:51 +000012622 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012623 comp = ctxt->comp;
12624 switch (op->op) {
12625 case XPATH_OP_END:
12626 return (0);
12627 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +000012628 bakd = ctxt->context->doc;
12629 bak = ctxt->context->node;
12630 pp = ctxt->context->proximityPosition;
12631 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012632 total =
12633 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012634 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012635 if ((ctxt->value != NULL)
12636 && (ctxt->value->type == XPATH_NODESET)
12637 && (ctxt->value->nodesetval != NULL)
12638 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12639 /*
12640 * limit tree traversing to first node in the result
12641 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012642 if (ctxt->value->nodesetval->nodeNr > 1)
12643 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012644 *last =
12645 ctxt->value->nodesetval->nodeTab[ctxt->value->
12646 nodesetval->nodeNr -
12647 1];
12648 }
William M. Brackce4fc562004-01-22 02:47:18 +000012649 ctxt->context->doc = bakd;
12650 ctxt->context->node = bak;
12651 ctxt->context->proximityPosition = pp;
12652 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012653 cur =
12654 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012655 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012656 if ((ctxt->value != NULL)
12657 && (ctxt->value->type == XPATH_NODESET)
12658 && (ctxt->value->nodesetval != NULL)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012659 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012660 }
12661 CHECK_TYPE0(XPATH_NODESET);
12662 arg2 = valuePop(ctxt);
12663
12664 CHECK_TYPE0(XPATH_NODESET);
12665 arg1 = valuePop(ctxt);
12666
12667 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12668 arg2->nodesetval);
12669 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012670 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012671 /* optimizer */
12672 if (total > cur)
12673 xmlXPathCompSwap(op);
12674 return (total + cur);
12675 case XPATH_OP_ROOT:
12676 xmlXPathRoot(ctxt);
12677 return (0);
12678 case XPATH_OP_NODE:
12679 if (op->ch1 != -1)
12680 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012681 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012682 if (op->ch2 != -1)
12683 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012684 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012685 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12686 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012687 return (total);
12688 case XPATH_OP_RESET:
12689 if (op->ch1 != -1)
12690 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012691 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012692 if (op->ch2 != -1)
12693 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012694 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012695 ctxt->context->node = NULL;
12696 return (total);
12697 case XPATH_OP_COLLECT:{
12698 if (op->ch1 == -1)
12699 return (0);
12700
12701 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012702 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012703
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012704 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012705 return (total);
12706 }
12707 case XPATH_OP_VALUE:
12708 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012709 xmlXPathCacheObjectCopy(ctxt->context,
12710 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012711 return (0);
12712 case XPATH_OP_SORT:
12713 if (op->ch1 != -1)
12714 total +=
12715 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12716 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012717 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012718 if ((ctxt->value != NULL)
12719 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012720 && (ctxt->value->nodesetval != NULL)
12721 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012722 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12723 return (total);
12724 default:
12725 return (xmlXPathCompOpEval(ctxt, op));
12726 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012727}
12728
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012729#ifdef XP_OPTIMIZED_FILTER_FIRST
12730static int
12731xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12732 xmlXPathStepOpPtr op, xmlNodePtr * first)
12733{
12734 int total = 0;
12735 xmlXPathCompExprPtr comp;
12736 xmlXPathObjectPtr res;
12737 xmlXPathObjectPtr obj;
12738 xmlNodeSetPtr oldset;
12739 xmlNodePtr oldnode;
12740 xmlDocPtr oldDoc;
12741 int i;
12742
12743 CHECK_ERROR0;
12744 comp = ctxt->comp;
12745 /*
12746 * Optimization for ()[last()] selection i.e. the last elem
12747 */
12748 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12749 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12750 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12751 int f = comp->steps[op->ch2].ch1;
12752
12753 if ((f != -1) &&
12754 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12755 (comp->steps[f].value5 == NULL) &&
12756 (comp->steps[f].value == 0) &&
12757 (comp->steps[f].value4 != NULL) &&
12758 (xmlStrEqual
12759 (comp->steps[f].value4, BAD_CAST "last"))) {
12760 xmlNodePtr last = NULL;
12761
12762 total +=
12763 xmlXPathCompOpEvalLast(ctxt,
12764 &comp->steps[op->ch1],
12765 &last);
12766 CHECK_ERROR0;
12767 /*
12768 * The nodeset should be in document order,
12769 * Keep only the last value
12770 */
12771 if ((ctxt->value != NULL) &&
12772 (ctxt->value->type == XPATH_NODESET) &&
12773 (ctxt->value->nodesetval != NULL) &&
12774 (ctxt->value->nodesetval->nodeTab != NULL) &&
12775 (ctxt->value->nodesetval->nodeNr > 1)) {
12776 ctxt->value->nodesetval->nodeTab[0] =
12777 ctxt->value->nodesetval->nodeTab[ctxt->
12778 value->
12779 nodesetval->
12780 nodeNr -
12781 1];
12782 ctxt->value->nodesetval->nodeNr = 1;
12783 *first = *(ctxt->value->nodesetval->nodeTab);
12784 }
12785 return (total);
12786 }
12787 }
12788
12789 if (op->ch1 != -1)
12790 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12791 CHECK_ERROR0;
12792 if (op->ch2 == -1)
12793 return (total);
12794 if (ctxt->value == NULL)
12795 return (total);
12796
12797#ifdef LIBXML_XPTR_ENABLED
12798 oldnode = ctxt->context->node;
12799 /*
12800 * Hum are we filtering the result of an XPointer expression
12801 */
12802 if (ctxt->value->type == XPATH_LOCATIONSET) {
12803 xmlXPathObjectPtr tmp = NULL;
12804 xmlLocationSetPtr newlocset = NULL;
12805 xmlLocationSetPtr oldlocset;
12806
12807 /*
12808 * Extract the old locset, and then evaluate the result of the
12809 * expression for all the element in the locset. use it to grow
12810 * up a new locset.
12811 */
12812 CHECK_TYPE0(XPATH_LOCATIONSET);
12813 obj = valuePop(ctxt);
12814 oldlocset = obj->user;
12815 ctxt->context->node = NULL;
12816
12817 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12818 ctxt->context->contextSize = 0;
12819 ctxt->context->proximityPosition = 0;
12820 if (op->ch2 != -1)
12821 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12822 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012823 if (res != NULL) {
12824 xmlXPathReleaseObject(ctxt->context, res);
12825 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012826 valuePush(ctxt, obj);
12827 CHECK_ERROR0;
12828 return (total);
12829 }
12830 newlocset = xmlXPtrLocationSetCreate(NULL);
12831
12832 for (i = 0; i < oldlocset->locNr; i++) {
12833 /*
12834 * Run the evaluation with a node list made of a
12835 * single item in the nodelocset.
12836 */
12837 ctxt->context->node = oldlocset->locTab[i]->user;
12838 ctxt->context->contextSize = oldlocset->locNr;
12839 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012840 if (tmp == NULL) {
12841 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12842 ctxt->context->node);
12843 } else {
12844 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12845 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012846 }
12847 valuePush(ctxt, tmp);
12848 if (op->ch2 != -1)
12849 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12850 if (ctxt->error != XPATH_EXPRESSION_OK) {
12851 xmlXPathFreeObject(obj);
12852 return(0);
12853 }
12854 /*
12855 * The result of the evaluation need to be tested to
12856 * decided whether the filter succeeded or not
12857 */
12858 res = valuePop(ctxt);
12859 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12860 xmlXPtrLocationSetAdd(newlocset,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012861 xmlXPathCacheObjectCopy(ctxt->context,
12862 oldlocset->locTab[i]));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012863 }
12864 /*
12865 * Cleanup
12866 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012867 if (res != NULL) {
12868 xmlXPathReleaseObject(ctxt->context, res);
12869 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012870 if (ctxt->value == tmp) {
12871 valuePop(ctxt);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012872 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012873 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012874 * REVISIT TODO: Don't create a temporary nodeset
12875 * for everly iteration.
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012876 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012877 /* OLD: xmlXPathFreeObject(res); */
12878 } else
12879 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012880 ctxt->context->node = NULL;
12881 /*
12882 * Only put the first node in the result, then leave.
12883 */
12884 if (newlocset->locNr > 0) {
12885 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
12886 break;
12887 }
12888 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012889 if (tmp != NULL) {
12890 xmlXPathReleaseObject(ctxt->context, tmp);
12891 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012892 /*
12893 * The result is used as the new evaluation locset.
12894 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012895 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012896 ctxt->context->node = NULL;
12897 ctxt->context->contextSize = -1;
12898 ctxt->context->proximityPosition = -1;
12899 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12900 ctxt->context->node = oldnode;
12901 return (total);
12902 }
12903#endif /* LIBXML_XPTR_ENABLED */
12904
12905 /*
12906 * Extract the old set, and then evaluate the result of the
12907 * expression for all the element in the set. use it to grow
12908 * up a new set.
12909 */
12910 CHECK_TYPE0(XPATH_NODESET);
12911 obj = valuePop(ctxt);
12912 oldset = obj->nodesetval;
12913
12914 oldnode = ctxt->context->node;
12915 oldDoc = ctxt->context->doc;
12916 ctxt->context->node = NULL;
12917
12918 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
12919 ctxt->context->contextSize = 0;
12920 ctxt->context->proximityPosition = 0;
12921 /* QUESTION TODO: Why was this code commented out?
12922 if (op->ch2 != -1)
12923 total +=
12924 xmlXPathCompOpEval(ctxt,
12925 &comp->steps[op->ch2]);
12926 CHECK_ERROR0;
12927 res = valuePop(ctxt);
12928 if (res != NULL)
12929 xmlXPathFreeObject(res);
12930 */
12931 valuePush(ctxt, obj);
12932 ctxt->context->node = oldnode;
12933 CHECK_ERROR0;
12934 } else {
12935 xmlNodeSetPtr newset;
12936 xmlXPathObjectPtr tmp = NULL;
12937 /*
12938 * Initialize the new set.
12939 * Also set the xpath document in case things like
12940 * key() evaluation are attempted on the predicate
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012941 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012942 newset = xmlXPathNodeSetCreate(NULL);
12943
12944 for (i = 0; i < oldset->nodeNr; i++) {
12945 /*
12946 * Run the evaluation with a node list made of
12947 * a single item in the nodeset.
12948 */
12949 ctxt->context->node = oldset->nodeTab[i];
12950 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
12951 (oldset->nodeTab[i]->doc != NULL))
12952 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012953 if (tmp == NULL) {
12954 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12955 ctxt->context->node);
12956 } else {
12957 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12958 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012959 }
12960 valuePush(ctxt, tmp);
12961 ctxt->context->contextSize = oldset->nodeNr;
12962 ctxt->context->proximityPosition = i + 1;
12963 if (op->ch2 != -1)
12964 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12965 if (ctxt->error != XPATH_EXPRESSION_OK) {
12966 xmlXPathFreeNodeSet(newset);
12967 xmlXPathFreeObject(obj);
12968 return(0);
12969 }
12970 /*
12971 * The result of the evaluation needs to be tested to
12972 * decide whether the filter succeeded or not
12973 */
12974 res = valuePop(ctxt);
12975 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12976 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
12977 }
12978 /*
12979 * Cleanup
12980 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012981 if (res != NULL) {
12982 xmlXPathReleaseObject(ctxt->context, res);
12983 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012984 if (ctxt->value == tmp) {
12985 valuePop(ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012986 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012987 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012988 * in order to avoid massive recreation inside this
12989 * loop.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012990 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012991 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012992 } else
12993 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012994 ctxt->context->node = NULL;
12995 /*
12996 * Only put the first node in the result, then leave.
12997 */
12998 if (newset->nodeNr > 0) {
12999 *first = *(newset->nodeTab);
13000 break;
13001 }
13002 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013003 if (tmp != NULL) {
13004 xmlXPathReleaseObject(ctxt->context, tmp);
13005 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013006 /*
13007 * The result is used as the new evaluation set.
13008 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013009 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013010 ctxt->context->node = NULL;
13011 ctxt->context->contextSize = -1;
13012 ctxt->context->proximityPosition = -1;
13013 /* may want to move this past the '}' later */
13014 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013015 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013016 }
13017 ctxt->context->node = oldnode;
13018 return(total);
13019}
13020#endif /* XP_OPTIMIZED_FILTER_FIRST */
13021
Owen Taylor3473f882001-02-23 17:55:21 +000013022/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013023 * xmlXPathCompOpEval:
13024 * @ctxt: the XPath parser context with the compiled expression
13025 * @op: an XPath compiled operation
13026 *
13027 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000013028 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013029 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013030static int
13031xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13032{
13033 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013034 int equal, ret;
13035 xmlXPathCompExprPtr comp;
13036 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013037 xmlNodePtr bak;
13038 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000013039 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000013040 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013041
Daniel Veillard556c6682001-10-06 09:59:51 +000013042 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013043 comp = ctxt->comp;
13044 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013045 case XPATH_OP_END:
13046 return (0);
13047 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013048 bakd = ctxt->context->doc;
13049 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013050 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013051 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013052 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013053 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013054 xmlXPathBooleanFunction(ctxt, 1);
13055 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13056 return (total);
13057 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013058 ctxt->context->doc = bakd;
13059 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013060 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013061 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013062 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013063 if (ctxt->error) {
13064 xmlXPathFreeObject(arg2);
13065 return(0);
13066 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013067 xmlXPathBooleanFunction(ctxt, 1);
13068 arg1 = valuePop(ctxt);
13069 arg1->boolval &= arg2->boolval;
13070 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013071 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013072 return (total);
13073 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013074 bakd = ctxt->context->doc;
13075 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013076 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013077 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013078 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013079 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013080 xmlXPathBooleanFunction(ctxt, 1);
13081 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13082 return (total);
13083 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013084 ctxt->context->doc = bakd;
13085 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013086 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013087 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013088 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013089 if (ctxt->error) {
13090 xmlXPathFreeObject(arg2);
13091 return(0);
13092 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013093 xmlXPathBooleanFunction(ctxt, 1);
13094 arg1 = valuePop(ctxt);
13095 arg1->boolval |= arg2->boolval;
13096 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013097 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013098 return (total);
13099 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013100 bakd = ctxt->context->doc;
13101 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013102 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013103 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013104 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013105 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013106 ctxt->context->doc = bakd;
13107 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013108 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013109 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013110 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013111 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000013112 if (op->value)
13113 equal = xmlXPathEqualValues(ctxt);
13114 else
13115 equal = xmlXPathNotEqualValues(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013116 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013117 return (total);
13118 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013119 bakd = ctxt->context->doc;
13120 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013121 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013122 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013123 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013124 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013125 ctxt->context->doc = bakd;
13126 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013127 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013128 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013129 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013130 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013131 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013132 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013133 return (total);
13134 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013135 bakd = ctxt->context->doc;
13136 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013137 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013138 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013139 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013140 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013141 if (op->ch2 != -1) {
13142 ctxt->context->doc = bakd;
13143 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013144 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013145 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013146 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013147 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013148 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013149 if (op->value == 0)
13150 xmlXPathSubValues(ctxt);
13151 else if (op->value == 1)
13152 xmlXPathAddValues(ctxt);
13153 else if (op->value == 2)
13154 xmlXPathValueFlipSign(ctxt);
13155 else if (op->value == 3) {
13156 CAST_TO_NUMBER;
13157 CHECK_TYPE0(XPATH_NUMBER);
13158 }
13159 return (total);
13160 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013161 bakd = ctxt->context->doc;
13162 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013163 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013164 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013165 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013166 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013167 ctxt->context->doc = bakd;
13168 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013169 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013170 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013171 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013172 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013173 if (op->value == 0)
13174 xmlXPathMultValues(ctxt);
13175 else if (op->value == 1)
13176 xmlXPathDivValues(ctxt);
13177 else if (op->value == 2)
13178 xmlXPathModValues(ctxt);
13179 return (total);
13180 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013181 bakd = ctxt->context->doc;
13182 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013183 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013184 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013185 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013186 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013187 ctxt->context->doc = bakd;
13188 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013189 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013190 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013191 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013192 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013193 CHECK_TYPE0(XPATH_NODESET);
13194 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013195
Daniel Veillardf06307e2001-07-03 10:35:50 +000013196 CHECK_TYPE0(XPATH_NODESET);
13197 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013198
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013199 if ((arg1->nodesetval == NULL) ||
13200 ((arg2->nodesetval != NULL) &&
13201 (arg2->nodesetval->nodeNr != 0)))
13202 {
13203 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13204 arg2->nodesetval);
13205 }
13206
Daniel Veillardf06307e2001-07-03 10:35:50 +000013207 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013208 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013209 return (total);
13210 case XPATH_OP_ROOT:
13211 xmlXPathRoot(ctxt);
13212 return (total);
13213 case XPATH_OP_NODE:
13214 if (op->ch1 != -1)
13215 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013216 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013217 if (op->ch2 != -1)
13218 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013219 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013220 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13221 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013222 return (total);
13223 case XPATH_OP_RESET:
13224 if (op->ch1 != -1)
13225 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013226 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013227 if (op->ch2 != -1)
13228 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013229 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013230 ctxt->context->node = NULL;
13231 return (total);
13232 case XPATH_OP_COLLECT:{
13233 if (op->ch1 == -1)
13234 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000013235
Daniel Veillardf06307e2001-07-03 10:35:50 +000013236 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013237 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013238
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013239 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013240 return (total);
13241 }
13242 case XPATH_OP_VALUE:
13243 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013244 xmlXPathCacheObjectCopy(ctxt->context,
13245 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013246 return (total);
13247 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000013248 xmlXPathObjectPtr val;
13249
Daniel Veillardf06307e2001-07-03 10:35:50 +000013250 if (op->ch1 != -1)
13251 total +=
13252 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013253 if (op->value5 == NULL) {
13254 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13255 if (val == NULL) {
13256 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13257 return(0);
13258 }
13259 valuePush(ctxt, val);
13260 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013261 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013262
Daniel Veillardf06307e2001-07-03 10:35:50 +000013263 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13264 if (URI == NULL) {
13265 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013266 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000013267 op->value4, op->value5);
13268 return (total);
13269 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013270 val = xmlXPathVariableLookupNS(ctxt->context,
13271 op->value4, URI);
13272 if (val == NULL) {
13273 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13274 return(0);
13275 }
13276 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013277 }
13278 return (total);
13279 }
13280 case XPATH_OP_FUNCTION:{
13281 xmlXPathFunction func;
13282 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000013283 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013284
13285 if (op->ch1 != -1)
13286 total +=
13287 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013288 if (ctxt->valueNr < op->value) {
13289 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013290 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013291 ctxt->error = XPATH_INVALID_OPERAND;
13292 return (total);
13293 }
13294 for (i = 0; i < op->value; i++)
13295 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13296 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013297 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013298 ctxt->error = XPATH_INVALID_OPERAND;
13299 return (total);
13300 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013301 if (op->cache != NULL)
William M. Brackad0e67c2004-12-01 14:35:10 +000013302 XML_CAST_FPTR(func) = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013303 else {
13304 const xmlChar *URI = NULL;
13305
13306 if (op->value5 == NULL)
13307 func =
13308 xmlXPathFunctionLookup(ctxt->context,
13309 op->value4);
13310 else {
13311 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13312 if (URI == NULL) {
13313 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013314 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000013315 op->value4, op->value5);
13316 return (total);
13317 }
13318 func = xmlXPathFunctionLookupNS(ctxt->context,
13319 op->value4, URI);
13320 }
13321 if (func == NULL) {
13322 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013323 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000013324 op->value4);
13325 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013326 }
William M. Brackad0e67c2004-12-01 14:35:10 +000013327 op->cache = XML_CAST_FPTR(func);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013328 op->cacheURI = (void *) URI;
13329 }
13330 oldFunc = ctxt->context->function;
13331 oldFuncURI = ctxt->context->functionURI;
13332 ctxt->context->function = op->value4;
13333 ctxt->context->functionURI = op->cacheURI;
13334 func(ctxt, op->value);
13335 ctxt->context->function = oldFunc;
13336 ctxt->context->functionURI = oldFuncURI;
13337 return (total);
13338 }
13339 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000013340 bakd = ctxt->context->doc;
13341 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000013342 pp = ctxt->context->proximityPosition;
13343 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013344 if (op->ch1 != -1)
13345 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
William M. Brack645a9242004-11-09 12:20:42 +000013346 ctxt->context->contextSize = cs;
13347 ctxt->context->proximityPosition = pp;
Daniel Veillard088bf112002-05-14 11:03:59 +000013348 ctxt->context->node = bak;
William M. Brack645a9242004-11-09 12:20:42 +000013349 ctxt->context->doc = bakd;
Daniel Veillard556c6682001-10-06 09:59:51 +000013350 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000013351 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013352 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000013353 ctxt->context->doc = bakd;
13354 ctxt->context->node = bak;
13355 CHECK_ERROR0;
13356 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013357 return (total);
13358 case XPATH_OP_PREDICATE:
13359 case XPATH_OP_FILTER:{
13360 xmlXPathObjectPtr res;
13361 xmlXPathObjectPtr obj, tmp;
13362 xmlNodeSetPtr newset = NULL;
13363 xmlNodeSetPtr oldset;
13364 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000013365 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013366 int i;
13367
13368 /*
13369 * Optimization for ()[1] selection i.e. the first elem
13370 */
13371 if ((op->ch1 != -1) && (op->ch2 != -1) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013372#ifdef XP_OPTIMIZED_FILTER_FIRST
13373 /*
13374 * FILTER TODO: Can we assume that the inner processing
13375 * will result in an ordered list if we have an
13376 * XPATH_OP_FILTER?
13377 * What about an additional field or flag on
13378 * xmlXPathObject like @sorted ? This way we wouln'd need
13379 * to assume anything, so it would be more robust and
13380 * easier to optimize.
13381 */
13382 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13383 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13384#else
13385 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13386#endif
13387 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013388 xmlXPathObjectPtr val;
13389
13390 val = comp->steps[op->ch2].value4;
13391 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13392 (val->floatval == 1.0)) {
13393 xmlNodePtr first = NULL;
13394
13395 total +=
13396 xmlXPathCompOpEvalFirst(ctxt,
13397 &comp->steps[op->ch1],
13398 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000013399 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013400 /*
13401 * The nodeset should be in document order,
13402 * Keep only the first value
13403 */
13404 if ((ctxt->value != NULL) &&
13405 (ctxt->value->type == XPATH_NODESET) &&
13406 (ctxt->value->nodesetval != NULL) &&
13407 (ctxt->value->nodesetval->nodeNr > 1))
13408 ctxt->value->nodesetval->nodeNr = 1;
13409 return (total);
13410 }
13411 }
13412 /*
13413 * Optimization for ()[last()] selection i.e. the last elem
13414 */
13415 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13416 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13417 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13418 int f = comp->steps[op->ch2].ch1;
13419
13420 if ((f != -1) &&
13421 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13422 (comp->steps[f].value5 == NULL) &&
13423 (comp->steps[f].value == 0) &&
13424 (comp->steps[f].value4 != NULL) &&
13425 (xmlStrEqual
13426 (comp->steps[f].value4, BAD_CAST "last"))) {
13427 xmlNodePtr last = NULL;
13428
13429 total +=
13430 xmlXPathCompOpEvalLast(ctxt,
13431 &comp->steps[op->ch1],
13432 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000013433 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013434 /*
13435 * The nodeset should be in document order,
13436 * Keep only the last value
13437 */
13438 if ((ctxt->value != NULL) &&
13439 (ctxt->value->type == XPATH_NODESET) &&
13440 (ctxt->value->nodesetval != NULL) &&
13441 (ctxt->value->nodesetval->nodeTab != NULL) &&
13442 (ctxt->value->nodesetval->nodeNr > 1)) {
13443 ctxt->value->nodesetval->nodeTab[0] =
13444 ctxt->value->nodesetval->nodeTab[ctxt->
13445 value->
13446 nodesetval->
13447 nodeNr -
13448 1];
13449 ctxt->value->nodesetval->nodeNr = 1;
13450 }
13451 return (total);
13452 }
13453 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013454 /*
13455 * Process inner predicates first.
13456 * Example "index[parent::book][1]":
13457 * ...
13458 * PREDICATE <-- we are here "[1]"
13459 * PREDICATE <-- process "[parent::book]" first
13460 * SORT
13461 * COLLECT 'parent' 'name' 'node' book
13462 * NODE
13463 * ELEM Object is a number : 1
13464 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013465 if (op->ch1 != -1)
13466 total +=
13467 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013468 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013469 if (op->ch2 == -1)
13470 return (total);
13471 if (ctxt->value == NULL)
13472 return (total);
13473
13474 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013475
13476#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013477 /*
13478 * Hum are we filtering the result of an XPointer expression
13479 */
13480 if (ctxt->value->type == XPATH_LOCATIONSET) {
13481 xmlLocationSetPtr newlocset = NULL;
13482 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013483
Daniel Veillardf06307e2001-07-03 10:35:50 +000013484 /*
13485 * Extract the old locset, and then evaluate the result of the
13486 * expression for all the element in the locset. use it to grow
13487 * up a new locset.
13488 */
13489 CHECK_TYPE0(XPATH_LOCATIONSET);
13490 obj = valuePop(ctxt);
13491 oldlocset = obj->user;
13492 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013493
Daniel Veillardf06307e2001-07-03 10:35:50 +000013494 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13495 ctxt->context->contextSize = 0;
13496 ctxt->context->proximityPosition = 0;
13497 if (op->ch2 != -1)
13498 total +=
13499 xmlXPathCompOpEval(ctxt,
13500 &comp->steps[op->ch2]);
13501 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013502 if (res != NULL) {
13503 xmlXPathReleaseObject(ctxt->context, res);
13504 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013505 valuePush(ctxt, obj);
13506 CHECK_ERROR0;
13507 return (total);
13508 }
13509 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013510
Daniel Veillardf06307e2001-07-03 10:35:50 +000013511 for (i = 0; i < oldlocset->locNr; i++) {
13512 /*
13513 * Run the evaluation with a node list made of a
13514 * single item in the nodelocset.
13515 */
13516 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013517 ctxt->context->contextSize = oldlocset->locNr;
13518 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013519 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13520 ctxt->context->node);
William M. Brackf7eb7942003-12-31 07:59:17 +000013521 valuePush(ctxt, tmp);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013522
Daniel Veillardf06307e2001-07-03 10:35:50 +000013523 if (op->ch2 != -1)
13524 total +=
13525 xmlXPathCompOpEval(ctxt,
13526 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013527 if (ctxt->error != XPATH_EXPRESSION_OK) {
13528 xmlXPathFreeObject(obj);
13529 return(0);
13530 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013531
Daniel Veillardf06307e2001-07-03 10:35:50 +000013532 /*
13533 * The result of the evaluation need to be tested to
13534 * decided whether the filter succeeded or not
13535 */
13536 res = valuePop(ctxt);
13537 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13538 xmlXPtrLocationSetAdd(newlocset,
13539 xmlXPathObjectCopy
13540 (oldlocset->locTab[i]));
13541 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013542
Daniel Veillardf06307e2001-07-03 10:35:50 +000013543 /*
13544 * Cleanup
13545 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013546 if (res != NULL) {
13547 xmlXPathReleaseObject(ctxt->context, res);
13548 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013549 if (ctxt->value == tmp) {
13550 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013551 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013552 }
13553
13554 ctxt->context->node = NULL;
13555 }
13556
13557 /*
13558 * The result is used as the new evaluation locset.
13559 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013560 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013561 ctxt->context->node = NULL;
13562 ctxt->context->contextSize = -1;
13563 ctxt->context->proximityPosition = -1;
13564 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13565 ctxt->context->node = oldnode;
13566 return (total);
13567 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013568#endif /* LIBXML_XPTR_ENABLED */
13569
Daniel Veillardf06307e2001-07-03 10:35:50 +000013570 /*
13571 * Extract the old set, and then evaluate the result of the
13572 * expression for all the element in the set. use it to grow
13573 * up a new set.
13574 */
13575 CHECK_TYPE0(XPATH_NODESET);
13576 obj = valuePop(ctxt);
13577 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000013578
Daniel Veillardf06307e2001-07-03 10:35:50 +000013579 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000013580 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013581 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013582
Daniel Veillardf06307e2001-07-03 10:35:50 +000013583 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13584 ctxt->context->contextSize = 0;
13585 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000013586/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000013587 if (op->ch2 != -1)
13588 total +=
13589 xmlXPathCompOpEval(ctxt,
13590 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013591 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013592 res = valuePop(ctxt);
13593 if (res != NULL)
13594 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000013595*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000013596 valuePush(ctxt, obj);
13597 ctxt->context->node = oldnode;
13598 CHECK_ERROR0;
13599 } else {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013600 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013601 /*
13602 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000013603 * Also set the xpath document in case things like
13604 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000013605 */
13606 newset = xmlXPathNodeSetCreate(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013607 /*
13608 * SPEC XPath 1.0:
13609 * "For each node in the node-set to be filtered, the
13610 * PredicateExpr is evaluated with that node as the
13611 * context node, with the number of nodes in the
13612 * node-set as the context size, and with the proximity
13613 * position of the node in the node-set with respect to
13614 * the axis as the context position;"
13615 * @oldset is the node-set" to be filtered.
13616 *
13617 * SPEC XPath 1.0:
13618 * "only predicates change the context position and
13619 * context size (see [2.4 Predicates])."
13620 * Example:
13621 * node-set context pos
13622 * nA 1
13623 * nB 2
13624 * nC 3
13625 * After applying predicate [position() > 1] :
13626 * node-set context pos
13627 * nB 1
13628 * nC 2
13629 *
13630 * removed the first node in the node-set, then
13631 * the context position of the
13632 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013633 for (i = 0; i < oldset->nodeNr; i++) {
13634 /*
13635 * Run the evaluation with a node list made of
13636 * a single item in the nodeset.
13637 */
13638 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000013639 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13640 (oldset->nodeTab[i]->doc != NULL))
13641 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013642 if (tmp == NULL) {
13643 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13644 ctxt->context->node);
13645 } else {
13646 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13647 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013648 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013649 valuePush(ctxt, tmp);
13650 ctxt->context->contextSize = oldset->nodeNr;
13651 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013652 /*
13653 * Evaluate the predicate against the context node.
13654 * Can/should we optimize position() predicates
13655 * here (e.g. "[1]")?
13656 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013657 if (op->ch2 != -1)
13658 total +=
13659 xmlXPathCompOpEval(ctxt,
13660 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013661 if (ctxt->error != XPATH_EXPRESSION_OK) {
13662 xmlXPathFreeNodeSet(newset);
13663 xmlXPathFreeObject(obj);
13664 return(0);
13665 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013666
Daniel Veillardf06307e2001-07-03 10:35:50 +000013667 /*
William M. Brack08171912003-12-29 02:52:11 +000013668 * The result of the evaluation needs to be tested to
13669 * decide whether the filter succeeded or not
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013670 */
13671 /*
13672 * OPTIMIZE TODO: Can we use
13673 * xmlXPathNodeSetAdd*Unique()* instead?
13674 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013675 res = valuePop(ctxt);
13676 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13677 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13678 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013679
Daniel Veillardf06307e2001-07-03 10:35:50 +000013680 /*
13681 * Cleanup
13682 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013683 if (res != NULL) {
13684 xmlXPathReleaseObject(ctxt->context, res);
13685 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013686 if (ctxt->value == tmp) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013687 valuePop(ctxt);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000013688 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013689 /*
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013690 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013691 * in order to avoid massive recreation inside this
13692 * loop.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013693 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013694 } else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013695 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013696 ctxt->context->node = NULL;
13697 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013698 if (tmp != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013699 xmlXPathReleaseObject(ctxt->context, tmp);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013700 /*
13701 * The result is used as the new evaluation set.
13702 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013703 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013704 ctxt->context->node = NULL;
13705 ctxt->context->contextSize = -1;
13706 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000013707 /* may want to move this past the '}' later */
13708 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013709 valuePush(ctxt,
13710 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013711 }
13712 ctxt->context->node = oldnode;
13713 return (total);
13714 }
13715 case XPATH_OP_SORT:
13716 if (op->ch1 != -1)
13717 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013718 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013719 if ((ctxt->value != NULL) &&
13720 (ctxt->value->type == XPATH_NODESET) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013721 (ctxt->value->nodesetval != NULL) &&
13722 (ctxt->value->nodesetval->nodeNr > 1))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013723 {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013724 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013725 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013726 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013727#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013728 case XPATH_OP_RANGETO:{
13729 xmlXPathObjectPtr range;
13730 xmlXPathObjectPtr res, obj;
13731 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000013732 xmlLocationSetPtr newlocset = NULL;
13733 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013734 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000013735 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013736
Daniel Veillardf06307e2001-07-03 10:35:50 +000013737 if (op->ch1 != -1)
13738 total +=
13739 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13740 if (op->ch2 == -1)
13741 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013742
William M. Brack08171912003-12-29 02:52:11 +000013743 if (ctxt->value->type == XPATH_LOCATIONSET) {
13744 /*
13745 * Extract the old locset, and then evaluate the result of the
13746 * expression for all the element in the locset. use it to grow
13747 * up a new locset.
13748 */
13749 CHECK_TYPE0(XPATH_LOCATIONSET);
13750 obj = valuePop(ctxt);
13751 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013752
William M. Brack08171912003-12-29 02:52:11 +000013753 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000013754 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000013755 ctxt->context->contextSize = 0;
13756 ctxt->context->proximityPosition = 0;
13757 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13758 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013759 if (res != NULL) {
13760 xmlXPathReleaseObject(ctxt->context, res);
13761 }
William M. Brack08171912003-12-29 02:52:11 +000013762 valuePush(ctxt, obj);
13763 CHECK_ERROR0;
13764 return (total);
13765 }
13766 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013767
William M. Brack08171912003-12-29 02:52:11 +000013768 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013769 /*
William M. Brack08171912003-12-29 02:52:11 +000013770 * Run the evaluation with a node list made of a
13771 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000013772 */
William M. Brackf7eb7942003-12-31 07:59:17 +000013773 ctxt->context->node = oldlocset->locTab[i]->user;
13774 ctxt->context->contextSize = oldlocset->locNr;
13775 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013776 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13777 ctxt->context->node);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013778 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013779
Daniel Veillardf06307e2001-07-03 10:35:50 +000013780 if (op->ch2 != -1)
13781 total +=
13782 xmlXPathCompOpEval(ctxt,
13783 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013784 if (ctxt->error != XPATH_EXPRESSION_OK) {
13785 xmlXPathFreeObject(obj);
13786 return(0);
13787 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013788
Daniel Veillardf06307e2001-07-03 10:35:50 +000013789 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000013790 if (res->type == XPATH_LOCATIONSET) {
13791 xmlLocationSetPtr rloc =
13792 (xmlLocationSetPtr)res->user;
13793 for (j=0; j<rloc->locNr; j++) {
13794 range = xmlXPtrNewRange(
13795 oldlocset->locTab[i]->user,
13796 oldlocset->locTab[i]->index,
13797 rloc->locTab[j]->user2,
13798 rloc->locTab[j]->index2);
13799 if (range != NULL) {
13800 xmlXPtrLocationSetAdd(newlocset, range);
13801 }
13802 }
13803 } else {
13804 range = xmlXPtrNewRangeNodeObject(
13805 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13806 if (range != NULL) {
13807 xmlXPtrLocationSetAdd(newlocset,range);
13808 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013809 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013810
Daniel Veillardf06307e2001-07-03 10:35:50 +000013811 /*
13812 * Cleanup
13813 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013814 if (res != NULL) {
13815 xmlXPathReleaseObject(ctxt->context, res);
13816 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013817 if (ctxt->value == tmp) {
13818 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013819 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013820 }
13821
13822 ctxt->context->node = NULL;
13823 }
William M. Brack72ee48d2003-12-30 08:30:19 +000013824 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000013825 CHECK_TYPE0(XPATH_NODESET);
13826 obj = valuePop(ctxt);
13827 oldset = obj->nodesetval;
13828 ctxt->context->node = NULL;
13829
13830 newlocset = xmlXPtrLocationSetCreate(NULL);
13831
13832 if (oldset != NULL) {
13833 for (i = 0; i < oldset->nodeNr; i++) {
13834 /*
13835 * Run the evaluation with a node list made of a single item
13836 * in the nodeset.
13837 */
13838 ctxt->context->node = oldset->nodeTab[i];
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013839 /*
13840 * OPTIMIZE TODO: Avoid recreation for every iteration.
13841 */
13842 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13843 ctxt->context->node);
William M. Brack08171912003-12-29 02:52:11 +000013844 valuePush(ctxt, tmp);
13845
13846 if (op->ch2 != -1)
13847 total +=
13848 xmlXPathCompOpEval(ctxt,
13849 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013850 if (ctxt->error != XPATH_EXPRESSION_OK) {
13851 xmlXPathFreeObject(obj);
13852 return(0);
13853 }
William M. Brack08171912003-12-29 02:52:11 +000013854
William M. Brack08171912003-12-29 02:52:11 +000013855 res = valuePop(ctxt);
13856 range =
13857 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13858 res);
13859 if (range != NULL) {
13860 xmlXPtrLocationSetAdd(newlocset, range);
13861 }
13862
13863 /*
13864 * Cleanup
13865 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013866 if (res != NULL) {
13867 xmlXPathReleaseObject(ctxt->context, res);
13868 }
William M. Brack08171912003-12-29 02:52:11 +000013869 if (ctxt->value == tmp) {
13870 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013871 xmlXPathReleaseObject(ctxt->context, res);
William M. Brack08171912003-12-29 02:52:11 +000013872 }
13873
13874 ctxt->context->node = NULL;
13875 }
13876 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013877 }
13878
13879 /*
13880 * The result is used as the new evaluation set.
13881 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013882 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013883 ctxt->context->node = NULL;
13884 ctxt->context->contextSize = -1;
13885 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000013886 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013887 return (total);
13888 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013889#endif /* LIBXML_XPTR_ENABLED */
13890 }
13891 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000013892 "XPath: unknown precompiled operation %d\n", op->op);
13893 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013894}
13895
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013896/**
13897 * xmlXPathCompOpEvalToBoolean:
13898 * @ctxt: the XPath parser context
13899 *
13900 * Evaluates if the expression evaluates to true.
13901 *
13902 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13903 */
13904static int
13905xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013906 xmlXPathStepOpPtr op,
13907 int isPredicate)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013908{
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013909 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013910
13911start:
13912 /* comp = ctxt->comp; */
13913 switch (op->op) {
13914 case XPATH_OP_END:
13915 return (0);
13916 case XPATH_OP_VALUE:
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013917 resObj = (xmlXPathObjectPtr) op->value4;
13918 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013919 case XPATH_OP_SORT:
13920 /*
13921 * We don't need sorting for boolean results. Skip this one.
13922 */
13923 if (op->ch1 != -1) {
13924 op = &ctxt->comp->steps[op->ch1];
13925 goto start;
13926 }
13927 return(0);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013928 case XPATH_OP_COLLECT:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013929 if (op->ch1 == -1)
13930 return(0);
13931
13932 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13933 if (ctxt->error != XPATH_EXPRESSION_OK)
13934 return(-1);
13935
13936 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13937 if (ctxt->error != XPATH_EXPRESSION_OK)
13938 return(-1);
13939
13940 resObj = valuePop(ctxt);
13941 if (resObj == NULL)
13942 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013943 break;
13944 default:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013945 /*
13946 * Fallback to call xmlXPathCompOpEval().
13947 */
13948 xmlXPathCompOpEval(ctxt, op);
13949 if (ctxt->error != XPATH_EXPRESSION_OK)
13950 return(-1);
13951
13952 resObj = valuePop(ctxt);
13953 if (resObj == NULL)
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013954 return(-1);
13955 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013956 }
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013957
13958 if (resObj) {
13959 int res;
13960
13961 if (resObj->type == XPATH_BOOLEAN) {
13962 res = resObj->boolval;
13963 } else if (isPredicate) {
13964 /*
13965 * For predicates a result of type "number" is handled
13966 * differently:
13967 * SPEC XPath 1.0:
13968 * "If the result is a number, the result will be converted
13969 * to true if the number is equal to the context position
13970 * and will be converted to false otherwise;"
13971 */
13972 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
13973 } else {
13974 res = xmlXPathCastToBoolean(resObj);
13975 }
13976 xmlXPathReleaseObject(ctxt->context, resObj);
13977 return(res);
13978 }
13979
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013980 return(0);
13981}
13982
Daniel Veillard56de87e2005-02-16 00:22:29 +000013983#ifdef XPATH_STREAMING
13984/**
13985 * xmlXPathRunStreamEval:
13986 * @ctxt: the XPath parser context with the compiled expression
13987 *
13988 * Evaluate the Precompiled Streamable XPath expression in the given context.
13989 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013990static int
13991xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
13992 xmlXPathObjectPtr *resultSeq, int toBool)
13993{
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013994 int max_depth, min_depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013995 int from_root;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013996 int ret, depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013997 int eval_all_nodes;
William M. Brack12d37ab2005-02-21 13:54:07 +000013998 xmlNodePtr cur = NULL, limit = NULL;
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000013999 xmlStreamCtxtPtr patstream = NULL;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014000
14001 int nb_nodes = 0;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014002
14003 if ((ctxt == NULL) || (comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014004 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014005 max_depth = xmlPatternMaxDepth(comp);
14006 if (max_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014007 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014008 if (max_depth == -2)
14009 max_depth = 10000;
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014010 min_depth = xmlPatternMinDepth(comp);
14011 if (min_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014012 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014013 from_root = xmlPatternFromRoot(comp);
14014 if (from_root < 0)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014015 return(-1);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014016#if 0
14017 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14018#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000014019
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014020 if (! toBool) {
14021 if (resultSeq == NULL)
14022 return(-1);
14023 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14024 if (*resultSeq == NULL)
14025 return(-1);
14026 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014027
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014028 /*
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014029 * handle the special cases of "/" amd "." being matched
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014030 */
14031 if (min_depth == 0) {
14032 if (from_root) {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014033 /* Select "/" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014034 if (toBool)
14035 return(1);
14036 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14037 (xmlNodePtr) ctxt->doc);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014038 } else {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014039 /* Select "self::node()" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014040 if (toBool)
14041 return(1);
14042 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014043 }
14044 }
14045 if (max_depth == 0) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014046 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014047 }
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014048
Daniel Veillard56de87e2005-02-16 00:22:29 +000014049 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000014050 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014051 } else if (ctxt->node != NULL) {
14052 switch (ctxt->node->type) {
14053 case XML_ELEMENT_NODE:
14054 case XML_DOCUMENT_NODE:
14055 case XML_DOCUMENT_FRAG_NODE:
14056 case XML_HTML_DOCUMENT_NODE:
14057#ifdef LIBXML_DOCB_ENABLED
14058 case XML_DOCB_DOCUMENT_NODE:
14059#endif
14060 cur = ctxt->node;
14061 break;
14062 case XML_ATTRIBUTE_NODE:
14063 case XML_TEXT_NODE:
14064 case XML_CDATA_SECTION_NODE:
14065 case XML_ENTITY_REF_NODE:
14066 case XML_ENTITY_NODE:
14067 case XML_PI_NODE:
14068 case XML_COMMENT_NODE:
14069 case XML_NOTATION_NODE:
14070 case XML_DTD_NODE:
14071 case XML_DOCUMENT_TYPE_NODE:
14072 case XML_ELEMENT_DECL:
14073 case XML_ATTRIBUTE_DECL:
14074 case XML_ENTITY_DECL:
14075 case XML_NAMESPACE_DECL:
14076 case XML_XINCLUDE_START:
14077 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000014078 break;
14079 }
14080 limit = cur;
14081 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014082 if (cur == NULL) {
14083 return(0);
14084 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014085
14086 patstream = xmlPatternGetStreamCtxt(comp);
14087 if (patstream == NULL) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014088 /*
14089 * QUESTION TODO: Is this an error?
14090 */
14091 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014092 }
14093
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014094 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014095
Daniel Veillard56de87e2005-02-16 00:22:29 +000014096 if (from_root) {
14097 ret = xmlStreamPush(patstream, NULL, NULL);
14098 if (ret < 0) {
14099 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014100 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014101 goto return_1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014102 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014103 }
14104 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014105 depth = 0;
14106 goto scan_children;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014107next_node:
Daniel Veillardd3ff7ef2006-02-27 19:43:17 +000014108 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014109 nb_nodes++;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014110
14111 switch (cur->type) {
14112 case XML_ELEMENT_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014113 case XML_TEXT_NODE:
14114 case XML_CDATA_SECTION_NODE:
14115 case XML_COMMENT_NODE:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014116 case XML_PI_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014117 if (cur->type == XML_ELEMENT_NODE) {
14118 ret = xmlStreamPush(patstream, cur->name,
Daniel Veillard56de87e2005-02-16 00:22:29 +000014119 (cur->ns ? cur->ns->href : NULL));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014120 } else if (eval_all_nodes)
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014121 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14122 else
14123 break;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014124
14125 if (ret < 0) {
14126 /* NOP. */
14127 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014128 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014129 goto return_1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014130 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014131 }
14132 if ((cur->children == NULL) || (depth >= max_depth)) {
14133 ret = xmlStreamPop(patstream);
14134 while (cur->next != NULL) {
14135 cur = cur->next;
14136 if ((cur->type != XML_ENTITY_DECL) &&
14137 (cur->type != XML_DTD_NODE))
14138 goto next_node;
14139 }
14140 }
14141 default:
14142 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014143 }
14144
Daniel Veillard56de87e2005-02-16 00:22:29 +000014145scan_children:
14146 if ((cur->children != NULL) && (depth < max_depth)) {
14147 /*
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014148 * Do not descend on entities declarations
Daniel Veillard56de87e2005-02-16 00:22:29 +000014149 */
14150 if (cur->children->type != XML_ENTITY_DECL) {
14151 cur = cur->children;
14152 depth++;
14153 /*
14154 * Skip DTDs
14155 */
14156 if (cur->type != XML_DTD_NODE)
14157 continue;
14158 }
14159 }
14160
14161 if (cur == limit)
14162 break;
14163
14164 while (cur->next != NULL) {
14165 cur = cur->next;
14166 if ((cur->type != XML_ENTITY_DECL) &&
14167 (cur->type != XML_DTD_NODE))
14168 goto next_node;
14169 }
14170
14171 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014172 cur = cur->parent;
14173 depth--;
14174 if ((cur == NULL) || (cur == limit))
14175 goto done;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014176 if (cur->type == XML_ELEMENT_NODE) {
14177 ret = xmlStreamPop(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014178 } else if ((eval_all_nodes) &&
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014179 ((cur->type == XML_TEXT_NODE) ||
14180 (cur->type == XML_CDATA_SECTION_NODE) ||
14181 (cur->type == XML_COMMENT_NODE) ||
14182 (cur->type == XML_PI_NODE)))
14183 {
14184 ret = xmlStreamPop(patstream);
14185 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014186 if (cur->next != NULL) {
14187 cur = cur->next;
14188 break;
14189 }
14190 } while (cur != NULL);
14191
14192 } while ((cur != NULL) && (depth >= 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014193
Daniel Veillard56de87e2005-02-16 00:22:29 +000014194done:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014195
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014196#if 0
14197 printf("stream eval: checked %d nodes selected %d\n",
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014198 nb_nodes, retObj->nodesetval->nodeNr);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014199#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014200
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014201 if (patstream)
14202 xmlFreeStreamCtxt(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014203 return(0);
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014204
14205return_1:
14206 if (patstream)
14207 xmlFreeStreamCtxt(patstream);
14208 return(1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014209}
14210#endif /* XPATH_STREAMING */
14211
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014212/**
14213 * xmlXPathRunEval:
14214 * @ctxt: the XPath parser context with the compiled expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014215 * @toBool: evaluate to a boolean result
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014216 *
14217 * Evaluate the Precompiled XPath expression in the given context.
14218 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014219static int
14220xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14221{
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014222 xmlXPathCompExprPtr comp;
14223
14224 if ((ctxt == NULL) || (ctxt->comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014225 return(-1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014226
14227 if (ctxt->valueTab == NULL) {
14228 /* Allocate the value stack */
14229 ctxt->valueTab = (xmlXPathObjectPtr *)
14230 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14231 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000014232 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014233 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014234 }
14235 ctxt->valueNr = 0;
14236 ctxt->valueMax = 10;
14237 ctxt->value = NULL;
14238 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014239#ifdef XPATH_STREAMING
14240 if (ctxt->comp->stream) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014241 int res;
14242
14243 if (toBool) {
14244 /*
14245 * Evaluation to boolean result.
14246 */
14247 res = xmlXPathRunStreamEval(ctxt->context,
14248 ctxt->comp->stream, NULL, 1);
14249 if (res != -1)
14250 return(res);
14251 } else {
14252 xmlXPathObjectPtr resObj = NULL;
14253
14254 /*
14255 * Evaluation to a sequence.
14256 */
14257 res = xmlXPathRunStreamEval(ctxt->context,
14258 ctxt->comp->stream, &resObj, 0);
14259
14260 if ((res != -1) && (resObj != NULL)) {
14261 valuePush(ctxt, resObj);
14262 return(0);
14263 }
14264 if (resObj != NULL)
14265 xmlXPathReleaseObject(ctxt->context, resObj);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014266 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014267 /*
14268 * QUESTION TODO: This falls back to normal XPath evaluation
14269 * if res == -1. Is this intended?
14270 */
Daniel Veillard56de87e2005-02-16 00:22:29 +000014271 }
14272#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014273 comp = ctxt->comp;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014274 if (comp->last < 0) {
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014275 xmlGenericError(xmlGenericErrorContext,
14276 "xmlXPathRunEval: last is less than zero\n");
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014277 return(-1);
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014278 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014279 if (toBool)
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014280 return(xmlXPathCompOpEvalToBoolean(ctxt,
14281 &comp->steps[comp->last], 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014282 else
14283 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14284
14285 return(0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014286}
14287
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014288/************************************************************************
14289 * *
14290 * Public interfaces *
14291 * *
14292 ************************************************************************/
14293
14294/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014295 * xmlXPathEvalPredicate:
14296 * @ctxt: the XPath context
14297 * @res: the Predicate Expression evaluation result
14298 *
14299 * Evaluate a predicate result for the current node.
14300 * A PredicateExpr is evaluated by evaluating the Expr and converting
14301 * the result to a boolean. If the result is a number, the result will
14302 * be converted to true if the number is equal to the position of the
14303 * context node in the context node list (as returned by the position
14304 * function) and will be converted to false otherwise; if the result
14305 * is not a number, then the result will be converted as if by a call
14306 * to the boolean function.
14307 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014308 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014309 */
14310int
14311xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014312 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014313 switch (res->type) {
14314 case XPATH_BOOLEAN:
14315 return(res->boolval);
14316 case XPATH_NUMBER:
14317 return(res->floatval == ctxt->proximityPosition);
14318 case XPATH_NODESET:
14319 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000014320 if (res->nodesetval == NULL)
14321 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014322 return(res->nodesetval->nodeNr != 0);
14323 case XPATH_STRING:
14324 return((res->stringval != NULL) &&
14325 (xmlStrlen(res->stringval) != 0));
14326 default:
14327 STRANGE
14328 }
14329 return(0);
14330}
14331
14332/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014333 * xmlXPathEvaluatePredicateResult:
14334 * @ctxt: the XPath Parser context
14335 * @res: the Predicate Expression evaluation result
14336 *
14337 * Evaluate a predicate result for the current node.
14338 * A PredicateExpr is evaluated by evaluating the Expr and converting
14339 * the result to a boolean. If the result is a number, the result will
14340 * be converted to true if the number is equal to the position of the
14341 * context node in the context node list (as returned by the position
14342 * function) and will be converted to false otherwise; if the result
14343 * is not a number, then the result will be converted as if by a call
14344 * to the boolean function.
14345 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014346 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014347 */
14348int
14349xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14350 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014351 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014352 switch (res->type) {
14353 case XPATH_BOOLEAN:
14354 return(res->boolval);
14355 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000014356#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000014357 return((res->floatval == ctxt->context->proximityPosition) &&
14358 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000014359#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014360 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000014361#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014362 case XPATH_NODESET:
14363 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000014364 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000014365 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014366 return(res->nodesetval->nodeNr != 0);
14367 case XPATH_STRING:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014368 return((res->stringval != NULL) && (res->stringval[0] != 0));
William M. Brack08171912003-12-29 02:52:11 +000014369#ifdef LIBXML_XPTR_ENABLED
14370 case XPATH_LOCATIONSET:{
14371 xmlLocationSetPtr ptr = res->user;
14372 if (ptr == NULL)
14373 return(0);
14374 return (ptr->locNr != 0);
14375 }
14376#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014377 default:
14378 STRANGE
14379 }
14380 return(0);
14381}
14382
Daniel Veillard56de87e2005-02-16 00:22:29 +000014383#ifdef XPATH_STREAMING
14384/**
14385 * xmlXPathTryStreamCompile:
14386 * @ctxt: an XPath context
14387 * @str: the XPath expression
14388 *
14389 * Try to compile the XPath expression as a streamable subset.
14390 *
14391 * Returns the compiled expression or NULL if failed to compile.
14392 */
14393static xmlXPathCompExprPtr
14394xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14395 /*
14396 * Optimization: use streaming patterns when the XPath expression can
14397 * be compiled to a stream lookup
14398 */
14399 xmlPatternPtr stream;
14400 xmlXPathCompExprPtr comp;
14401 xmlDictPtr dict = NULL;
14402 const xmlChar **namespaces = NULL;
14403 xmlNsPtr ns;
14404 int i, j;
14405
14406 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14407 (!xmlStrchr(str, '@'))) {
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014408 const xmlChar *tmp;
14409
14410 /*
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014411 * We don't try to handle expressions using the verbose axis
14412 * specifiers ("::"), just the simplied form at this point.
14413 * Additionally, if there is no list of namespaces available and
14414 * there's a ":" in the expression, indicating a prefixed QName,
14415 * then we won't try to compile either. xmlPatterncompile() needs
14416 * to have a list of namespaces at compilation time in order to
14417 * compile prefixed name tests.
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014418 */
14419 tmp = xmlStrchr(str, ':');
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014420 if ((tmp != NULL) &&
14421 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14422 return(NULL);
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014423
Daniel Veillard56de87e2005-02-16 00:22:29 +000014424 if (ctxt != NULL) {
14425 dict = ctxt->dict;
14426 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000014427 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000014428 if (namespaces == NULL) {
14429 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14430 return(NULL);
14431 }
14432 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14433 ns = ctxt->namespaces[j];
14434 namespaces[i++] = ns->href;
14435 namespaces[i++] = ns->prefix;
14436 }
14437 namespaces[i++] = NULL;
14438 namespaces[i++] = NULL;
14439 }
14440 }
14441
William M. Brackea152c02005-06-09 18:12:28 +000014442 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14443 &namespaces[0]);
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014444 if (namespaces != NULL) {
14445 xmlFree((xmlChar **)namespaces);
14446 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014447 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14448 comp = xmlXPathNewCompExpr();
14449 if (comp == NULL) {
14450 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14451 return(NULL);
14452 }
14453 comp->stream = stream;
14454 comp->dict = dict;
14455 if (comp->dict)
14456 xmlDictReference(comp->dict);
14457 return(comp);
14458 }
14459 xmlFreePattern(stream);
14460 }
14461 return(NULL);
14462}
14463#endif /* XPATH_STREAMING */
14464
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014465static int
14466xmlXPathCanRewriteDosExpression(xmlChar *expr)
14467{
14468 if (expr == NULL)
14469 return(0);
14470 do {
14471 if ((*expr == '/') && (*(++expr) == '/'))
14472 return(1);
14473 } while (*expr++);
14474 return(0);
14475}
14476static void
14477xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14478{
14479 /*
14480 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14481 * internal representation.
14482 */
14483 if (op->ch1 != -1) {
14484 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14485 ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
14486 ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
14487 ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
14488 {
14489 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014490 * This is a "child::foo"
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014491 */
14492 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14493
14494 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14495 (prevop->ch1 != -1) &&
14496 ((xmlXPathAxisVal) prevop->value ==
14497 AXIS_DESCENDANT_OR_SELF) &&
14498 (prevop->ch2 == -1) &&
14499 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014500 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
14501 (comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014502 {
14503 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014504 * This is a "/descendant-or-self::node()" without predicates.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014505 * Eliminate it.
14506 */
14507 op->ch1 = prevop->ch1;
14508 op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
14509 }
14510 }
14511 if (op->ch1 != -1)
14512 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
14513 }
14514 if (op->ch2 != -1)
14515 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
14516}
14517
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014518/**
Daniel Veillard4773df22004-01-23 13:15:13 +000014519 * xmlXPathCtxtCompile:
14520 * @ctxt: an XPath context
14521 * @str: the XPath expression
14522 *
14523 * Compile an XPath expression
14524 *
14525 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14526 * the caller has to free the object.
14527 */
14528xmlXPathCompExprPtr
14529xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14530 xmlXPathParserContextPtr pctxt;
14531 xmlXPathCompExprPtr comp;
14532
Daniel Veillard56de87e2005-02-16 00:22:29 +000014533#ifdef XPATH_STREAMING
14534 comp = xmlXPathTryStreamCompile(ctxt, str);
14535 if (comp != NULL)
14536 return(comp);
14537#endif
14538
Daniel Veillard4773df22004-01-23 13:15:13 +000014539 xmlXPathInit();
14540
14541 pctxt = xmlXPathNewParserContext(str, ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014542 xmlXPathCompileExpr(pctxt, 1);
Daniel Veillard4773df22004-01-23 13:15:13 +000014543
14544 if( pctxt->error != XPATH_EXPRESSION_OK )
14545 {
14546 xmlXPathFreeParserContext(pctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000014547 return(NULL);
Daniel Veillard4773df22004-01-23 13:15:13 +000014548 }
14549
14550 if (*pctxt->cur != 0) {
14551 /*
14552 * aleksey: in some cases this line prints *second* error message
14553 * (see bug #78858) and probably this should be fixed.
14554 * However, we are not sure that all error messages are printed
14555 * out in other places. It's not critical so we leave it as-is for now
14556 */
14557 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14558 comp = NULL;
14559 } else {
14560 comp = pctxt->comp;
14561 pctxt->comp = NULL;
14562 }
14563 xmlXPathFreeParserContext(pctxt);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014564
Daniel Veillard4773df22004-01-23 13:15:13 +000014565 if (comp != NULL) {
14566 comp->expr = xmlStrdup(str);
14567#ifdef DEBUG_EVAL_COUNTS
14568 comp->string = xmlStrdup(str);
14569 comp->nb = 0;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014570#endif
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014571 if ((comp->expr != NULL) &&
14572 (comp->nbStep > 2) &&
14573 (comp->last >= 0) &&
Kasimier T. Buchcik7cb3fa92006-06-06 15:27:46 +000014574 (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
14575 {
14576 xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014577 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014578 }
Daniel Veillard4773df22004-01-23 13:15:13 +000014579 return(comp);
14580}
14581
14582/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014583 * xmlXPathCompile:
14584 * @str: the XPath expression
14585 *
14586 * Compile an XPath expression
14587 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000014588 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014589 * the caller has to free the object.
14590 */
14591xmlXPathCompExprPtr
14592xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000014593 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014594}
14595
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014596/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014597 * xmlXPathCompiledEvalInternal:
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014598 * @comp: the compiled XPath expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014599 * @ctxt: the XPath context
14600 * @resObj: the resulting XPath object or NULL
14601 * @toBool: 1 if only a boolean result is requested
Owen Taylor3473f882001-02-23 17:55:21 +000014602 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014603 * Evaluate the Precompiled XPath expression in the given context.
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014604 * The caller has to free @resObj.
Owen Taylor3473f882001-02-23 17:55:21 +000014605 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014606 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000014607 * the caller has to free the object.
14608 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014609static int
14610xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14611 xmlXPathContextPtr ctxt,
14612 xmlXPathObjectPtr *resObj,
14613 int toBool)
14614{
14615 xmlXPathParserContextPtr pctxt;
Daniel Veillard81463942001-10-16 12:34:39 +000014616#ifndef LIBXML_THREAD_ENABLED
14617 static int reentance = 0;
14618#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014619 int res;
Owen Taylor3473f882001-02-23 17:55:21 +000014620
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014621 CHECK_CTXT_NEG(ctxt)
William M. Brackf13f77f2004-11-12 16:03:48 +000014622
14623 if (comp == NULL)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014624 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +000014625 xmlXPathInit();
14626
Daniel Veillard81463942001-10-16 12:34:39 +000014627#ifndef LIBXML_THREAD_ENABLED
14628 reentance++;
14629 if (reentance > 1)
14630 xmlXPathDisableOptimizer = 1;
14631#endif
14632
Daniel Veillardf06307e2001-07-03 10:35:50 +000014633#ifdef DEBUG_EVAL_COUNTS
14634 comp->nb++;
14635 if ((comp->string != NULL) && (comp->nb > 100)) {
14636 fprintf(stderr, "100 x %s\n", comp->string);
14637 comp->nb = 0;
14638 }
14639#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014640 pctxt = xmlXPathCompParserContext(comp, ctxt);
14641 res = xmlXPathRunEval(pctxt, toBool);
Owen Taylor3473f882001-02-23 17:55:21 +000014642
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014643 if (resObj) {
14644 if (pctxt->value == NULL) {
14645 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014646 "xmlXPathCompiledEval: evaluation failed\n");
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014647 *resObj = NULL;
14648 } else {
14649 *resObj = valuePop(pctxt);
14650 }
Owen Taylor3473f882001-02-23 17:55:21 +000014651 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014652
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014653 /*
14654 * Pop all remaining objects from the stack.
14655 */
14656 if (pctxt->valueNr > 0) {
14657 xmlXPathObjectPtr tmp;
14658 int stack = 0;
14659
14660 do {
14661 tmp = valuePop(pctxt);
14662 if (tmp != NULL) {
14663 if (tmp != NULL)
14664 stack++;
14665 xmlXPathReleaseObject(ctxt, tmp);
14666 }
14667 } while (tmp != NULL);
14668 if ((stack != 0) &&
14669 ((toBool) || ((resObj) && (*resObj))))
14670 {
14671 xmlGenericError(xmlGenericErrorContext,
14672 "xmlXPathCompiledEval: %d objects left on the stack.\n",
14673 stack);
14674 }
Owen Taylor3473f882001-02-23 17:55:21 +000014675 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014676
14677 if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14678 xmlXPathFreeObject(*resObj);
14679 *resObj = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014680 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014681 pctxt->comp = NULL;
14682 xmlXPathFreeParserContext(pctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000014683#ifndef LIBXML_THREAD_ENABLED
14684 reentance--;
14685#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014686
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014687 return(res);
14688}
14689
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014690/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014691 * xmlXPathCompiledEval:
14692 * @comp: the compiled XPath expression
14693 * @ctx: the XPath context
14694 *
14695 * Evaluate the Precompiled XPath expression in the given context.
14696 *
14697 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14698 * the caller has to free the object.
14699 */
14700xmlXPathObjectPtr
14701xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14702{
14703 xmlXPathObjectPtr res = NULL;
14704
14705 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14706 return(res);
14707}
14708
14709/**
14710 * xmlXPathCompiledEvalToBoolean:
14711 * @comp: the compiled XPath expression
14712 * @ctxt: the XPath context
14713 *
14714 * Applies the XPath boolean() function on the result of the given
14715 * compiled expression.
14716 *
14717 * Returns 1 if the expression evaluated to true, 0 if to false and
14718 * -1 in API and internal errors.
14719 */
14720int
14721xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14722 xmlXPathContextPtr ctxt)
14723{
14724 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14725}
14726
14727/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014728 * xmlXPathEvalExpr:
14729 * @ctxt: the XPath Parser context
14730 *
14731 * Parse and evaluate an XPath expression in the given context,
14732 * then push the result on the context stack
14733 */
14734void
14735xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014736#ifdef XPATH_STREAMING
14737 xmlXPathCompExprPtr comp;
14738#endif
14739
Daniel Veillarda82b1822004-11-08 16:24:57 +000014740 if (ctxt == NULL) return;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014741
14742#ifdef XPATH_STREAMING
14743 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14744 if (comp != NULL) {
14745 if (ctxt->comp != NULL)
14746 xmlXPathFreeCompExpr(ctxt->comp);
14747 ctxt->comp = comp;
14748 if (ctxt->cur != NULL)
14749 while (*ctxt->cur != 0) ctxt->cur++;
14750 } else
14751#endif
14752 {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014753 xmlXPathCompileExpr(ctxt, 1);
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014754 /*
14755 * In this scenario the expression string will sit in ctxt->base.
14756 */
14757 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
14758 (ctxt->comp != NULL) &&
14759 (ctxt->base != NULL) &&
Kasimier T. Buchcik7cb3fa92006-06-06 15:27:46 +000014760 (ctxt->comp->nbStep > 2) &&
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014761 (ctxt->comp->last >= 0) &&
14762 (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014763 {
14764 xmlXPathRewriteDOSExpression(ctxt->comp,
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014765 &ctxt->comp->steps[ctxt->comp->last]);
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014766 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014767 }
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000014768 CHECK_ERROR;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014769 xmlXPathRunEval(ctxt, 0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014770}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014771
14772/**
14773 * xmlXPathEval:
14774 * @str: the XPath expression
14775 * @ctx: the XPath context
14776 *
14777 * Evaluate the XPath Location Path in the given context.
14778 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014779 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014780 * the caller has to free the object.
14781 */
14782xmlXPathObjectPtr
14783xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14784 xmlXPathParserContextPtr ctxt;
14785 xmlXPathObjectPtr res, tmp, init = NULL;
14786 int stack = 0;
14787
William M. Brackf13f77f2004-11-12 16:03:48 +000014788 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014789
William M. Brackf13f77f2004-11-12 16:03:48 +000014790 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014791
14792 ctxt = xmlXPathNewParserContext(str, ctx);
14793 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014794
14795 if (ctxt->value == NULL) {
14796 xmlGenericError(xmlGenericErrorContext,
14797 "xmlXPathEval: evaluation failed\n");
14798 res = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014799 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
14800#ifdef XPATH_STREAMING
14801 && (ctxt->comp->stream == NULL)
14802#endif
14803 ) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014804 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14805 res = NULL;
14806 } else {
14807 res = valuePop(ctxt);
14808 }
14809
14810 do {
14811 tmp = valuePop(ctxt);
14812 if (tmp != NULL) {
14813 if (tmp != init)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014814 stack++;
14815 xmlXPathReleaseObject(ctx, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014816 }
14817 } while (tmp != NULL);
14818 if ((stack != 0) && (res != NULL)) {
14819 xmlGenericError(xmlGenericErrorContext,
14820 "xmlXPathEval: %d object left on the stack\n",
14821 stack);
14822 }
14823 if (ctxt->error != XPATH_EXPRESSION_OK) {
14824 xmlXPathFreeObject(res);
14825 res = NULL;
14826 }
14827
Owen Taylor3473f882001-02-23 17:55:21 +000014828 xmlXPathFreeParserContext(ctxt);
14829 return(res);
14830}
14831
14832/**
14833 * xmlXPathEvalExpression:
14834 * @str: the XPath expression
14835 * @ctxt: the XPath context
14836 *
14837 * Evaluate the XPath expression in the given context.
14838 *
14839 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14840 * the caller has to free the object.
14841 */
14842xmlXPathObjectPtr
14843xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14844 xmlXPathParserContextPtr pctxt;
14845 xmlXPathObjectPtr res, tmp;
14846 int stack = 0;
14847
William M. Brackf13f77f2004-11-12 16:03:48 +000014848 CHECK_CTXT(ctxt)
Owen Taylor3473f882001-02-23 17:55:21 +000014849
William M. Brackf13f77f2004-11-12 16:03:48 +000014850 xmlXPathInit();
Owen Taylor3473f882001-02-23 17:55:21 +000014851
14852 pctxt = xmlXPathNewParserContext(str, ctxt);
14853 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000014854
14855 if (*pctxt->cur != 0) {
14856 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14857 res = NULL;
14858 } else {
14859 res = valuePop(pctxt);
14860 }
14861 do {
14862 tmp = valuePop(pctxt);
14863 if (tmp != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014864 xmlXPathReleaseObject(ctxt, tmp);
Owen Taylor3473f882001-02-23 17:55:21 +000014865 stack++;
14866 }
14867 } while (tmp != NULL);
14868 if ((stack != 0) && (res != NULL)) {
14869 xmlGenericError(xmlGenericErrorContext,
14870 "xmlXPathEvalExpression: %d object left on the stack\n",
14871 stack);
14872 }
14873 xmlXPathFreeParserContext(pctxt);
14874 return(res);
14875}
14876
Daniel Veillard42766c02002-08-22 20:52:17 +000014877/************************************************************************
14878 * *
14879 * Extra functions not pertaining to the XPath spec *
14880 * *
14881 ************************************************************************/
14882/**
14883 * xmlXPathEscapeUriFunction:
14884 * @ctxt: the XPath Parser context
14885 * @nargs: the number of arguments
14886 *
14887 * Implement the escape-uri() XPath function
14888 * string escape-uri(string $str, bool $escape-reserved)
14889 *
14890 * This function applies the URI escaping rules defined in section 2 of [RFC
14891 * 2396] to the string supplied as $uri-part, which typically represents all
14892 * or part of a URI. The effect of the function is to replace any special
14893 * character in the string by an escape sequence of the form %xx%yy...,
14894 * where xxyy... is the hexadecimal representation of the octets used to
14895 * represent the character in UTF-8.
14896 *
14897 * The set of characters that are escaped depends on the setting of the
14898 * boolean argument $escape-reserved.
14899 *
14900 * If $escape-reserved is true, all characters are escaped other than lower
14901 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14902 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14903 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14904 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14905 * A-F).
14906 *
14907 * If $escape-reserved is false, the behavior differs in that characters
14908 * referred to in [RFC 2396] as reserved characters are not escaped. These
14909 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14910 *
14911 * [RFC 2396] does not define whether escaped URIs should use lower case or
14912 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14913 * compared using string comparison functions, this function must always use
14914 * the upper-case letters A-F.
14915 *
14916 * Generally, $escape-reserved should be set to true when escaping a string
14917 * that is to form a single part of a URI, and to false when escaping an
14918 * entire URI or URI reference.
14919 *
14920 * In the case of non-ascii characters, the string is encoded according to
14921 * utf-8 and then converted according to RFC 2396.
14922 *
14923 * Examples
14924 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14925 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14926 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14927 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14928 *
14929 */
Daniel Veillard118aed72002-09-24 14:13:13 +000014930static void
Daniel Veillard42766c02002-08-22 20:52:17 +000014931xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14932 xmlXPathObjectPtr str;
14933 int escape_reserved;
14934 xmlBufferPtr target;
14935 xmlChar *cptr;
14936 xmlChar escape[4];
14937
14938 CHECK_ARITY(2);
14939
14940 escape_reserved = xmlXPathPopBoolean(ctxt);
14941
14942 CAST_TO_STRING;
14943 str = valuePop(ctxt);
14944
14945 target = xmlBufferCreate();
14946
14947 escape[0] = '%';
14948 escape[3] = 0;
14949
14950 if (target) {
14951 for (cptr = str->stringval; *cptr; cptr++) {
14952 if ((*cptr >= 'A' && *cptr <= 'Z') ||
14953 (*cptr >= 'a' && *cptr <= 'z') ||
14954 (*cptr >= '0' && *cptr <= '9') ||
14955 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
14956 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
14957 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14958 (*cptr == '%' &&
14959 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14960 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14961 (cptr[1] >= '0' && cptr[1] <= '9')) &&
14962 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14963 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14964 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14965 (!escape_reserved &&
14966 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14967 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14968 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14969 *cptr == ','))) {
14970 xmlBufferAdd(target, cptr, 1);
14971 } else {
14972 if ((*cptr >> 4) < 10)
14973 escape[1] = '0' + (*cptr >> 4);
14974 else
14975 escape[1] = 'A' - 10 + (*cptr >> 4);
14976 if ((*cptr & 0xF) < 10)
14977 escape[2] = '0' + (*cptr & 0xF);
14978 else
14979 escape[2] = 'A' - 10 + (*cptr & 0xF);
14980
14981 xmlBufferAdd(target, &escape[0], 3);
14982 }
14983 }
14984 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014985 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
14986 xmlBufferContent(target)));
Daniel Veillard42766c02002-08-22 20:52:17 +000014987 xmlBufferFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014988 xmlXPathReleaseObject(ctxt->context, str);
Daniel Veillard42766c02002-08-22 20:52:17 +000014989}
14990
Owen Taylor3473f882001-02-23 17:55:21 +000014991/**
14992 * xmlXPathRegisterAllFunctions:
14993 * @ctxt: the XPath context
14994 *
14995 * Registers all default XPath functions in this context
14996 */
14997void
14998xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
14999{
15000 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15001 xmlXPathBooleanFunction);
15002 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15003 xmlXPathCeilingFunction);
15004 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15005 xmlXPathCountFunction);
15006 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15007 xmlXPathConcatFunction);
15008 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15009 xmlXPathContainsFunction);
15010 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15011 xmlXPathIdFunction);
15012 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15013 xmlXPathFalseFunction);
15014 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15015 xmlXPathFloorFunction);
15016 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15017 xmlXPathLastFunction);
15018 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15019 xmlXPathLangFunction);
15020 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15021 xmlXPathLocalNameFunction);
15022 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15023 xmlXPathNotFunction);
15024 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15025 xmlXPathNameFunction);
15026 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15027 xmlXPathNamespaceURIFunction);
15028 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15029 xmlXPathNormalizeFunction);
15030 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15031 xmlXPathNumberFunction);
15032 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15033 xmlXPathPositionFunction);
15034 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15035 xmlXPathRoundFunction);
15036 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15037 xmlXPathStringFunction);
15038 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15039 xmlXPathStringLengthFunction);
15040 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15041 xmlXPathStartsWithFunction);
15042 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15043 xmlXPathSubstringFunction);
15044 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15045 xmlXPathSubstringBeforeFunction);
15046 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15047 xmlXPathSubstringAfterFunction);
15048 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15049 xmlXPathSumFunction);
15050 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15051 xmlXPathTrueFunction);
15052 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15053 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000015054
15055 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15056 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15057 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000015058}
15059
15060#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000015061#define bottom_xpath
15062#include "elfgcchack.h"