blob: 80c16857f535e8c69a3ecc0bddad4c48445bfa94 [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,
602 xmlXPathStepOpPtr op);
603
604/************************************************************************
605 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000606 * Parser Type functions *
607 * *
608 ************************************************************************/
609
610/**
611 * xmlXPathNewCompExpr:
612 *
613 * Create a new Xpath component
614 *
615 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
616 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000617static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000618xmlXPathNewCompExpr(void) {
619 xmlXPathCompExprPtr cur;
620
621 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
622 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000623 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000624 return(NULL);
625 }
626 memset(cur, 0, sizeof(xmlXPathCompExpr));
627 cur->maxStep = 10;
628 cur->nbStep = 0;
629 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
630 sizeof(xmlXPathStepOp));
631 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000632 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000633 xmlFree(cur);
634 return(NULL);
635 }
636 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
637 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000638#ifdef DEBUG_EVAL_COUNTS
639 cur->nb = 0;
640#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000641 return(cur);
642}
643
644/**
645 * xmlXPathFreeCompExpr:
646 * @comp: an XPATH comp
647 *
648 * Free up the memory allocated by @comp
649 */
650void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000651xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
652{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000653 xmlXPathStepOpPtr op;
654 int i;
655
656 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000657 return;
Daniel Veillard4773df22004-01-23 13:15:13 +0000658 if (comp->dict == NULL) {
659 for (i = 0; i < comp->nbStep; i++) {
660 op = &comp->steps[i];
661 if (op->value4 != NULL) {
662 if (op->op == XPATH_OP_VALUE)
663 xmlXPathFreeObject(op->value4);
664 else
665 xmlFree(op->value4);
666 }
667 if (op->value5 != NULL)
668 xmlFree(op->value5);
669 }
670 } else {
671 for (i = 0; i < comp->nbStep; i++) {
672 op = &comp->steps[i];
673 if (op->value4 != NULL) {
674 if (op->op == XPATH_OP_VALUE)
675 xmlXPathFreeObject(op->value4);
676 }
677 }
678 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000679 }
680 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000681 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000682 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000683#ifdef DEBUG_EVAL_COUNTS
684 if (comp->string != NULL) {
685 xmlFree(comp->string);
686 }
687#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000688#ifdef XPATH_STREAMING
689 if (comp->stream != NULL) {
690 xmlFreePatternList(comp->stream);
691 }
692#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000693 if (comp->expr != NULL) {
694 xmlFree(comp->expr);
695 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000696
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000697 xmlFree(comp);
698}
699
700/**
701 * xmlXPathCompExprAdd:
702 * @comp: the compiled expression
703 * @ch1: first child index
704 * @ch2: second child index
705 * @op: an op
706 * @value: the first int value
707 * @value2: the second int value
708 * @value3: the third int value
709 * @value4: the first string value
710 * @value5: the second string value
711 *
William M. Brack08171912003-12-29 02:52:11 +0000712 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000713 *
714 * Returns -1 in case of failure, the index otherwise
715 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000716static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000717xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
718 xmlXPathOp op, int value,
719 int value2, int value3, void *value4, void *value5) {
720 if (comp->nbStep >= comp->maxStep) {
721 xmlXPathStepOp *real;
722
723 comp->maxStep *= 2;
724 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
725 comp->maxStep * sizeof(xmlXPathStepOp));
726 if (real == NULL) {
727 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000728 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000729 return(-1);
730 }
731 comp->steps = real;
732 }
733 comp->last = comp->nbStep;
Kasimier T. Buchcik6422d912006-06-26 14:31:53 +0000734 comp->steps[comp->nbStep].rewriteType = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000735 comp->steps[comp->nbStep].ch1 = ch1;
736 comp->steps[comp->nbStep].ch2 = ch2;
737 comp->steps[comp->nbStep].op = op;
738 comp->steps[comp->nbStep].value = value;
739 comp->steps[comp->nbStep].value2 = value2;
740 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +0000741 if ((comp->dict != NULL) &&
742 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
743 (op == XPATH_OP_COLLECT))) {
744 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000745 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000746 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000747 xmlFree(value4);
748 } else
749 comp->steps[comp->nbStep].value4 = NULL;
750 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000751 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000752 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000753 xmlFree(value5);
754 } else
755 comp->steps[comp->nbStep].value5 = NULL;
756 } else {
757 comp->steps[comp->nbStep].value4 = value4;
758 comp->steps[comp->nbStep].value5 = value5;
759 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000760 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000761 return(comp->nbStep++);
762}
763
Daniel Veillardf06307e2001-07-03 10:35:50 +0000764/**
765 * xmlXPathCompSwap:
766 * @comp: the compiled expression
767 * @op: operation index
768 *
769 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000770 */
771static void
772xmlXPathCompSwap(xmlXPathStepOpPtr op) {
773 int tmp;
774
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000775#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000776 /*
777 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +0000778 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +0000779 * application
780 */
781 if (xmlXPathDisableOptimizer)
782 return;
783#endif
784
Daniel Veillardf06307e2001-07-03 10:35:50 +0000785 tmp = op->ch1;
786 op->ch1 = op->ch2;
787 op->ch2 = tmp;
788}
789
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000790#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
791 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
792 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000793#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
794 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
795 (op), (val), (val2), (val3), (val4), (val5))
796
797#define PUSH_LEAVE_EXPR(op, val, val2) \
798xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
799
800#define PUSH_UNARY_EXPR(op, ch, val, val2) \
801xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
802
803#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +0000804xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
805 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000806
807/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000808 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000809 * XPath object cache structures *
810 * *
811 ************************************************************************/
812
813/* #define XP_DEFAULT_CACHE_ON */
814
Kasimier T. Buchcik58694692006-05-31 12:37:28 +0000815#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000816
Kasimier T. Buchcik58694692006-05-31 12:37:28 +0000817typedef struct _xmlXPathContextCache xmlXPathContextCache;
818typedef xmlXPathContextCache *xmlXPathContextCachePtr;
819struct _xmlXPathContextCache {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +0000820 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
821 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
822 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
823 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
824 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000825 int maxNodeset;
826 int maxString;
827 int maxBoolean;
828 int maxNumber;
829 int maxMisc;
830#ifdef XP_DEBUG_OBJ_USAGE
831 int dbgCachedAll;
832 int dbgCachedNodeset;
833 int dbgCachedString;
834 int dbgCachedBool;
835 int dbgCachedNumber;
836 int dbgCachedPoint;
837 int dbgCachedRange;
838 int dbgCachedLocset;
839 int dbgCachedUsers;
840 int dbgCachedXSLTTree;
841 int dbgCachedUndefined;
842
843
844 int dbgReusedAll;
845 int dbgReusedNodeset;
846 int dbgReusedString;
847 int dbgReusedBool;
848 int dbgReusedNumber;
849 int dbgReusedPoint;
850 int dbgReusedRange;
851 int dbgReusedLocset;
852 int dbgReusedUsers;
853 int dbgReusedXSLTTree;
854 int dbgReusedUndefined;
855
856#endif
857};
858
859/************************************************************************
860 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000861 * Debugging related functions *
862 * *
863 ************************************************************************/
864
Owen Taylor3473f882001-02-23 17:55:21 +0000865#define STRANGE \
866 xmlGenericError(xmlGenericErrorContext, \
867 "Internal error at %s:%d\n", \
868 __FILE__, __LINE__);
869
870#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000871static void
872xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000873 int i;
874 char shift[100];
875
876 for (i = 0;((i < depth) && (i < 25));i++)
877 shift[2 * i] = shift[2 * i + 1] = ' ';
878 shift[2 * i] = shift[2 * i + 1] = 0;
879 if (cur == NULL) {
880 fprintf(output, shift);
881 fprintf(output, "Node is NULL !\n");
882 return;
883
884 }
885
886 if ((cur->type == XML_DOCUMENT_NODE) ||
887 (cur->type == XML_HTML_DOCUMENT_NODE)) {
888 fprintf(output, shift);
889 fprintf(output, " /\n");
890 } else if (cur->type == XML_ATTRIBUTE_NODE)
891 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
892 else
893 xmlDebugDumpOneNode(output, cur, depth);
894}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000895static void
896xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000897 xmlNodePtr tmp;
898 int i;
899 char shift[100];
900
901 for (i = 0;((i < depth) && (i < 25));i++)
902 shift[2 * i] = shift[2 * i + 1] = ' ';
903 shift[2 * i] = shift[2 * i + 1] = 0;
904 if (cur == NULL) {
905 fprintf(output, shift);
906 fprintf(output, "Node is NULL !\n");
907 return;
908
909 }
910
911 while (cur != NULL) {
912 tmp = cur;
913 cur = cur->next;
914 xmlDebugDumpOneNode(output, tmp, depth);
915 }
916}
Owen Taylor3473f882001-02-23 17:55:21 +0000917
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000918static void
919xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000920 int i;
921 char shift[100];
922
923 for (i = 0;((i < depth) && (i < 25));i++)
924 shift[2 * i] = shift[2 * i + 1] = ' ';
925 shift[2 * i] = shift[2 * i + 1] = 0;
926
927 if (cur == NULL) {
928 fprintf(output, shift);
929 fprintf(output, "NodeSet is NULL !\n");
930 return;
931
932 }
933
Daniel Veillard911f49a2001-04-07 15:39:35 +0000934 if (cur != NULL) {
935 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
936 for (i = 0;i < cur->nodeNr;i++) {
937 fprintf(output, shift);
938 fprintf(output, "%d", i + 1);
939 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
940 }
Owen Taylor3473f882001-02-23 17:55:21 +0000941 }
942}
943
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000944static void
945xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000946 int i;
947 char shift[100];
948
949 for (i = 0;((i < depth) && (i < 25));i++)
950 shift[2 * i] = shift[2 * i + 1] = ' ';
951 shift[2 * i] = shift[2 * i + 1] = 0;
952
953 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
954 fprintf(output, shift);
955 fprintf(output, "Value Tree is NULL !\n");
956 return;
957
958 }
959
960 fprintf(output, shift);
961 fprintf(output, "%d", i + 1);
962 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
963}
Owen Taylor3473f882001-02-23 17:55:21 +0000964#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000965static void
966xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000967 int i;
968 char shift[100];
969
970 for (i = 0;((i < depth) && (i < 25));i++)
971 shift[2 * i] = shift[2 * i + 1] = ' ';
972 shift[2 * i] = shift[2 * i + 1] = 0;
973
974 if (cur == NULL) {
975 fprintf(output, shift);
976 fprintf(output, "LocationSet is NULL !\n");
977 return;
978
979 }
980
981 for (i = 0;i < cur->locNr;i++) {
982 fprintf(output, shift);
983 fprintf(output, "%d : ", i + 1);
984 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
985 }
986}
Daniel Veillard017b1082001-06-21 11:20:21 +0000987#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000988
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000989/**
990 * xmlXPathDebugDumpObject:
991 * @output: the FILE * to dump the output
992 * @cur: the object to inspect
993 * @depth: indentation level
994 *
995 * Dump the content of the object for debugging purposes
996 */
997void
998xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000999 int i;
1000 char shift[100];
1001
Daniel Veillarda82b1822004-11-08 16:24:57 +00001002 if (output == NULL) return;
1003
Owen Taylor3473f882001-02-23 17:55:21 +00001004 for (i = 0;((i < depth) && (i < 25));i++)
1005 shift[2 * i] = shift[2 * i + 1] = ' ';
1006 shift[2 * i] = shift[2 * i + 1] = 0;
1007
Kasimier T. Buchcik97258712006-01-05 12:30:43 +00001008
1009 fprintf(output, shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001010
1011 if (cur == NULL) {
1012 fprintf(output, "Object is empty (NULL)\n");
1013 return;
1014 }
1015 switch(cur->type) {
1016 case XPATH_UNDEFINED:
1017 fprintf(output, "Object is uninitialized\n");
1018 break;
1019 case XPATH_NODESET:
1020 fprintf(output, "Object is a Node Set :\n");
1021 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1022 break;
1023 case XPATH_XSLT_TREE:
1024 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001025 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +00001026 break;
1027 case XPATH_BOOLEAN:
1028 fprintf(output, "Object is a Boolean : ");
1029 if (cur->boolval) fprintf(output, "true\n");
1030 else fprintf(output, "false\n");
1031 break;
1032 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +00001033 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001034 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001035 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001036 break;
1037 case -1:
1038 fprintf(output, "Object is a number : -Infinity\n");
1039 break;
1040 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001041 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001042 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001043 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1044 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001045 } else {
1046 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1047 }
1048 }
Owen Taylor3473f882001-02-23 17:55:21 +00001049 break;
1050 case XPATH_STRING:
1051 fprintf(output, "Object is a string : ");
1052 xmlDebugDumpString(output, cur->stringval);
1053 fprintf(output, "\n");
1054 break;
1055 case XPATH_POINT:
1056 fprintf(output, "Object is a point : index %d in node", cur->index);
1057 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1058 fprintf(output, "\n");
1059 break;
1060 case XPATH_RANGE:
1061 if ((cur->user2 == NULL) ||
1062 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1063 fprintf(output, "Object is a collapsed range :\n");
1064 fprintf(output, shift);
1065 if (cur->index >= 0)
1066 fprintf(output, "index %d in ", cur->index);
1067 fprintf(output, "node\n");
1068 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1069 depth + 1);
1070 } else {
1071 fprintf(output, "Object is a range :\n");
1072 fprintf(output, shift);
1073 fprintf(output, "From ");
1074 if (cur->index >= 0)
1075 fprintf(output, "index %d in ", cur->index);
1076 fprintf(output, "node\n");
1077 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1078 depth + 1);
1079 fprintf(output, shift);
1080 fprintf(output, "To ");
1081 if (cur->index2 >= 0)
1082 fprintf(output, "index %d in ", cur->index2);
1083 fprintf(output, "node\n");
1084 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1085 depth + 1);
1086 fprintf(output, "\n");
1087 }
1088 break;
1089 case XPATH_LOCATIONSET:
1090#if defined(LIBXML_XPTR_ENABLED)
1091 fprintf(output, "Object is a Location Set:\n");
1092 xmlXPathDebugDumpLocationSet(output,
1093 (xmlLocationSetPtr) cur->user, depth);
1094#endif
1095 break;
1096 case XPATH_USERS:
1097 fprintf(output, "Object is user defined\n");
1098 break;
1099 }
1100}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001101
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001102static void
1103xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001104 xmlXPathStepOpPtr op, int depth) {
1105 int i;
1106 char shift[100];
1107
1108 for (i = 0;((i < depth) && (i < 25));i++)
1109 shift[2 * i] = shift[2 * i + 1] = ' ';
1110 shift[2 * i] = shift[2 * i + 1] = 0;
1111
1112 fprintf(output, shift);
1113 if (op == NULL) {
1114 fprintf(output, "Step is NULL\n");
1115 return;
1116 }
1117 switch (op->op) {
1118 case XPATH_OP_END:
1119 fprintf(output, "END"); break;
1120 case XPATH_OP_AND:
1121 fprintf(output, "AND"); break;
1122 case XPATH_OP_OR:
1123 fprintf(output, "OR"); break;
1124 case XPATH_OP_EQUAL:
1125 if (op->value)
1126 fprintf(output, "EQUAL =");
1127 else
1128 fprintf(output, "EQUAL !=");
1129 break;
1130 case XPATH_OP_CMP:
1131 if (op->value)
1132 fprintf(output, "CMP <");
1133 else
1134 fprintf(output, "CMP >");
1135 if (!op->value2)
1136 fprintf(output, "=");
1137 break;
1138 case XPATH_OP_PLUS:
1139 if (op->value == 0)
1140 fprintf(output, "PLUS -");
1141 else if (op->value == 1)
1142 fprintf(output, "PLUS +");
1143 else if (op->value == 2)
1144 fprintf(output, "PLUS unary -");
1145 else if (op->value == 3)
1146 fprintf(output, "PLUS unary - -");
1147 break;
1148 case XPATH_OP_MULT:
1149 if (op->value == 0)
1150 fprintf(output, "MULT *");
1151 else if (op->value == 1)
1152 fprintf(output, "MULT div");
1153 else
1154 fprintf(output, "MULT mod");
1155 break;
1156 case XPATH_OP_UNION:
1157 fprintf(output, "UNION"); break;
1158 case XPATH_OP_ROOT:
1159 fprintf(output, "ROOT"); break;
1160 case XPATH_OP_NODE:
1161 fprintf(output, "NODE"); break;
1162 case XPATH_OP_RESET:
1163 fprintf(output, "RESET"); break;
1164 case XPATH_OP_SORT:
1165 fprintf(output, "SORT"); break;
1166 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +00001167 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1168 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1169 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001170 const xmlChar *prefix = op->value4;
1171 const xmlChar *name = op->value5;
1172
1173 fprintf(output, "COLLECT ");
1174 switch (axis) {
1175 case AXIS_ANCESTOR:
1176 fprintf(output, " 'ancestors' "); break;
1177 case AXIS_ANCESTOR_OR_SELF:
1178 fprintf(output, " 'ancestors-or-self' "); break;
1179 case AXIS_ATTRIBUTE:
1180 fprintf(output, " 'attributes' "); break;
1181 case AXIS_CHILD:
1182 fprintf(output, " 'child' "); break;
1183 case AXIS_DESCENDANT:
1184 fprintf(output, " 'descendant' "); break;
1185 case AXIS_DESCENDANT_OR_SELF:
1186 fprintf(output, " 'descendant-or-self' "); break;
1187 case AXIS_FOLLOWING:
1188 fprintf(output, " 'following' "); break;
1189 case AXIS_FOLLOWING_SIBLING:
1190 fprintf(output, " 'following-siblings' "); break;
1191 case AXIS_NAMESPACE:
1192 fprintf(output, " 'namespace' "); break;
1193 case AXIS_PARENT:
1194 fprintf(output, " 'parent' "); break;
1195 case AXIS_PRECEDING:
1196 fprintf(output, " 'preceding' "); break;
1197 case AXIS_PRECEDING_SIBLING:
1198 fprintf(output, " 'preceding-sibling' "); break;
1199 case AXIS_SELF:
1200 fprintf(output, " 'self' "); break;
1201 }
1202 switch (test) {
1203 case NODE_TEST_NONE:
1204 fprintf(output, "'none' "); break;
1205 case NODE_TEST_TYPE:
1206 fprintf(output, "'type' "); break;
1207 case NODE_TEST_PI:
1208 fprintf(output, "'PI' "); break;
1209 case NODE_TEST_ALL:
1210 fprintf(output, "'all' "); break;
1211 case NODE_TEST_NS:
1212 fprintf(output, "'namespace' "); break;
1213 case NODE_TEST_NAME:
1214 fprintf(output, "'name' "); break;
1215 }
1216 switch (type) {
1217 case NODE_TYPE_NODE:
1218 fprintf(output, "'node' "); break;
1219 case NODE_TYPE_COMMENT:
1220 fprintf(output, "'comment' "); break;
1221 case NODE_TYPE_TEXT:
1222 fprintf(output, "'text' "); break;
1223 case NODE_TYPE_PI:
1224 fprintf(output, "'PI' "); break;
1225 }
1226 if (prefix != NULL)
1227 fprintf(output, "%s:", prefix);
1228 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001229 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001230 break;
1231
1232 }
1233 case XPATH_OP_VALUE: {
1234 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1235
1236 fprintf(output, "ELEM ");
1237 xmlXPathDebugDumpObject(output, object, 0);
1238 goto finish;
1239 }
1240 case XPATH_OP_VARIABLE: {
1241 const xmlChar *prefix = op->value5;
1242 const xmlChar *name = op->value4;
1243
1244 if (prefix != NULL)
1245 fprintf(output, "VARIABLE %s:%s", prefix, name);
1246 else
1247 fprintf(output, "VARIABLE %s", name);
1248 break;
1249 }
1250 case XPATH_OP_FUNCTION: {
1251 int nbargs = op->value;
1252 const xmlChar *prefix = op->value5;
1253 const xmlChar *name = op->value4;
1254
1255 if (prefix != NULL)
1256 fprintf(output, "FUNCTION %s:%s(%d args)",
1257 prefix, name, nbargs);
1258 else
1259 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1260 break;
1261 }
1262 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1263 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001264 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001265#ifdef LIBXML_XPTR_ENABLED
1266 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1267#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001268 default:
1269 fprintf(output, "UNKNOWN %d\n", op->op); return;
1270 }
1271 fprintf(output, "\n");
1272finish:
1273 if (op->ch1 >= 0)
1274 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1275 if (op->ch2 >= 0)
1276 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1277}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001278
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001279/**
1280 * xmlXPathDebugDumpCompExpr:
1281 * @output: the FILE * for the output
1282 * @comp: the precompiled XPath expression
1283 * @depth: the indentation level.
1284 *
1285 * Dumps the tree of the compiled XPath expression.
1286 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001287void
1288xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1289 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001290 int i;
1291 char shift[100];
1292
Daniel Veillarda82b1822004-11-08 16:24:57 +00001293 if ((output == NULL) || (comp == NULL)) return;
1294
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001295 for (i = 0;((i < depth) && (i < 25));i++)
1296 shift[2 * i] = shift[2 * i + 1] = ' ';
1297 shift[2 * i] = shift[2 * i + 1] = 0;
1298
1299 fprintf(output, shift);
1300
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001301 fprintf(output, "Compiled Expression : %d elements\n",
1302 comp->nbStep);
1303 i = comp->last;
1304 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1305}
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001306
1307#ifdef XP_DEBUG_OBJ_USAGE
1308
1309/*
1310* XPath object usage related debugging variables.
1311*/
1312static int xmlXPathDebugObjCounterUndefined = 0;
1313static int xmlXPathDebugObjCounterNodeset = 0;
1314static int xmlXPathDebugObjCounterBool = 0;
1315static int xmlXPathDebugObjCounterNumber = 0;
1316static int xmlXPathDebugObjCounterString = 0;
1317static int xmlXPathDebugObjCounterPoint = 0;
1318static int xmlXPathDebugObjCounterRange = 0;
1319static int xmlXPathDebugObjCounterLocset = 0;
1320static int xmlXPathDebugObjCounterUsers = 0;
1321static int xmlXPathDebugObjCounterXSLTTree = 0;
1322static int xmlXPathDebugObjCounterAll = 0;
1323
1324static int xmlXPathDebugObjTotalUndefined = 0;
1325static int xmlXPathDebugObjTotalNodeset = 0;
1326static int xmlXPathDebugObjTotalBool = 0;
1327static int xmlXPathDebugObjTotalNumber = 0;
1328static int xmlXPathDebugObjTotalString = 0;
1329static int xmlXPathDebugObjTotalPoint = 0;
1330static int xmlXPathDebugObjTotalRange = 0;
1331static int xmlXPathDebugObjTotalLocset = 0;
1332static int xmlXPathDebugObjTotalUsers = 0;
1333static int xmlXPathDebugObjTotalXSLTTree = 0;
1334static int xmlXPathDebugObjTotalAll = 0;
1335
1336static int xmlXPathDebugObjMaxUndefined = 0;
1337static int xmlXPathDebugObjMaxNodeset = 0;
1338static int xmlXPathDebugObjMaxBool = 0;
1339static int xmlXPathDebugObjMaxNumber = 0;
1340static int xmlXPathDebugObjMaxString = 0;
1341static int xmlXPathDebugObjMaxPoint = 0;
1342static int xmlXPathDebugObjMaxRange = 0;
1343static int xmlXPathDebugObjMaxLocset = 0;
1344static int xmlXPathDebugObjMaxUsers = 0;
1345static int xmlXPathDebugObjMaxXSLTTree = 0;
1346static int xmlXPathDebugObjMaxAll = 0;
1347
1348/* REVISIT TODO: Make this static when committing */
1349static void
1350xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1351{
1352 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001353 if (ctxt->cache != NULL) {
1354 xmlXPathContextCachePtr cache =
1355 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001356
1357 cache->dbgCachedAll = 0;
1358 cache->dbgCachedNodeset = 0;
1359 cache->dbgCachedString = 0;
1360 cache->dbgCachedBool = 0;
1361 cache->dbgCachedNumber = 0;
1362 cache->dbgCachedPoint = 0;
1363 cache->dbgCachedRange = 0;
1364 cache->dbgCachedLocset = 0;
1365 cache->dbgCachedUsers = 0;
1366 cache->dbgCachedXSLTTree = 0;
1367 cache->dbgCachedUndefined = 0;
1368
1369 cache->dbgReusedAll = 0;
1370 cache->dbgReusedNodeset = 0;
1371 cache->dbgReusedString = 0;
1372 cache->dbgReusedBool = 0;
1373 cache->dbgReusedNumber = 0;
1374 cache->dbgReusedPoint = 0;
1375 cache->dbgReusedRange = 0;
1376 cache->dbgReusedLocset = 0;
1377 cache->dbgReusedUsers = 0;
1378 cache->dbgReusedXSLTTree = 0;
1379 cache->dbgReusedUndefined = 0;
1380 }
1381 }
1382
1383 xmlXPathDebugObjCounterUndefined = 0;
1384 xmlXPathDebugObjCounterNodeset = 0;
1385 xmlXPathDebugObjCounterBool = 0;
1386 xmlXPathDebugObjCounterNumber = 0;
1387 xmlXPathDebugObjCounterString = 0;
1388 xmlXPathDebugObjCounterPoint = 0;
1389 xmlXPathDebugObjCounterRange = 0;
1390 xmlXPathDebugObjCounterLocset = 0;
1391 xmlXPathDebugObjCounterUsers = 0;
1392 xmlXPathDebugObjCounterXSLTTree = 0;
1393 xmlXPathDebugObjCounterAll = 0;
1394
1395 xmlXPathDebugObjTotalUndefined = 0;
1396 xmlXPathDebugObjTotalNodeset = 0;
1397 xmlXPathDebugObjTotalBool = 0;
1398 xmlXPathDebugObjTotalNumber = 0;
1399 xmlXPathDebugObjTotalString = 0;
1400 xmlXPathDebugObjTotalPoint = 0;
1401 xmlXPathDebugObjTotalRange = 0;
1402 xmlXPathDebugObjTotalLocset = 0;
1403 xmlXPathDebugObjTotalUsers = 0;
1404 xmlXPathDebugObjTotalXSLTTree = 0;
1405 xmlXPathDebugObjTotalAll = 0;
1406
1407 xmlXPathDebugObjMaxUndefined = 0;
1408 xmlXPathDebugObjMaxNodeset = 0;
1409 xmlXPathDebugObjMaxBool = 0;
1410 xmlXPathDebugObjMaxNumber = 0;
1411 xmlXPathDebugObjMaxString = 0;
1412 xmlXPathDebugObjMaxPoint = 0;
1413 xmlXPathDebugObjMaxRange = 0;
1414 xmlXPathDebugObjMaxLocset = 0;
1415 xmlXPathDebugObjMaxUsers = 0;
1416 xmlXPathDebugObjMaxXSLTTree = 0;
1417 xmlXPathDebugObjMaxAll = 0;
1418
1419}
1420
1421static void
1422xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1423 xmlXPathObjectType objType)
1424{
1425 int isCached = 0;
1426
1427 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001428 if (ctxt->cache != NULL) {
1429 xmlXPathContextCachePtr cache =
1430 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001431
1432 isCached = 1;
1433
1434 cache->dbgReusedAll++;
1435 switch (objType) {
1436 case XPATH_UNDEFINED:
1437 cache->dbgReusedUndefined++;
1438 break;
1439 case XPATH_NODESET:
1440 cache->dbgReusedNodeset++;
1441 break;
1442 case XPATH_BOOLEAN:
1443 cache->dbgReusedBool++;
1444 break;
1445 case XPATH_NUMBER:
1446 cache->dbgReusedNumber++;
1447 break;
1448 case XPATH_STRING:
1449 cache->dbgReusedString++;
1450 break;
1451 case XPATH_POINT:
1452 cache->dbgReusedPoint++;
1453 break;
1454 case XPATH_RANGE:
1455 cache->dbgReusedRange++;
1456 break;
1457 case XPATH_LOCATIONSET:
1458 cache->dbgReusedLocset++;
1459 break;
1460 case XPATH_USERS:
1461 cache->dbgReusedUsers++;
1462 break;
1463 case XPATH_XSLT_TREE:
1464 cache->dbgReusedXSLTTree++;
1465 break;
1466 default:
1467 break;
1468 }
1469 }
1470 }
1471
1472 switch (objType) {
1473 case XPATH_UNDEFINED:
1474 if (! isCached)
1475 xmlXPathDebugObjTotalUndefined++;
1476 xmlXPathDebugObjCounterUndefined++;
1477 if (xmlXPathDebugObjCounterUndefined >
1478 xmlXPathDebugObjMaxUndefined)
1479 xmlXPathDebugObjMaxUndefined =
1480 xmlXPathDebugObjCounterUndefined;
1481 break;
1482 case XPATH_NODESET:
1483 if (! isCached)
1484 xmlXPathDebugObjTotalNodeset++;
1485 xmlXPathDebugObjCounterNodeset++;
1486 if (xmlXPathDebugObjCounterNodeset >
1487 xmlXPathDebugObjMaxNodeset)
1488 xmlXPathDebugObjMaxNodeset =
1489 xmlXPathDebugObjCounterNodeset;
1490 break;
1491 case XPATH_BOOLEAN:
1492 if (! isCached)
1493 xmlXPathDebugObjTotalBool++;
1494 xmlXPathDebugObjCounterBool++;
1495 if (xmlXPathDebugObjCounterBool >
1496 xmlXPathDebugObjMaxBool)
1497 xmlXPathDebugObjMaxBool =
1498 xmlXPathDebugObjCounterBool;
1499 break;
1500 case XPATH_NUMBER:
1501 if (! isCached)
1502 xmlXPathDebugObjTotalNumber++;
1503 xmlXPathDebugObjCounterNumber++;
1504 if (xmlXPathDebugObjCounterNumber >
1505 xmlXPathDebugObjMaxNumber)
1506 xmlXPathDebugObjMaxNumber =
1507 xmlXPathDebugObjCounterNumber;
1508 break;
1509 case XPATH_STRING:
1510 if (! isCached)
1511 xmlXPathDebugObjTotalString++;
1512 xmlXPathDebugObjCounterString++;
1513 if (xmlXPathDebugObjCounterString >
1514 xmlXPathDebugObjMaxString)
1515 xmlXPathDebugObjMaxString =
1516 xmlXPathDebugObjCounterString;
1517 break;
1518 case XPATH_POINT:
1519 if (! isCached)
1520 xmlXPathDebugObjTotalPoint++;
1521 xmlXPathDebugObjCounterPoint++;
1522 if (xmlXPathDebugObjCounterPoint >
1523 xmlXPathDebugObjMaxPoint)
1524 xmlXPathDebugObjMaxPoint =
1525 xmlXPathDebugObjCounterPoint;
1526 break;
1527 case XPATH_RANGE:
1528 if (! isCached)
1529 xmlXPathDebugObjTotalRange++;
1530 xmlXPathDebugObjCounterRange++;
1531 if (xmlXPathDebugObjCounterRange >
1532 xmlXPathDebugObjMaxRange)
1533 xmlXPathDebugObjMaxRange =
1534 xmlXPathDebugObjCounterRange;
1535 break;
1536 case XPATH_LOCATIONSET:
1537 if (! isCached)
1538 xmlXPathDebugObjTotalLocset++;
1539 xmlXPathDebugObjCounterLocset++;
1540 if (xmlXPathDebugObjCounterLocset >
1541 xmlXPathDebugObjMaxLocset)
1542 xmlXPathDebugObjMaxLocset =
1543 xmlXPathDebugObjCounterLocset;
1544 break;
1545 case XPATH_USERS:
1546 if (! isCached)
1547 xmlXPathDebugObjTotalUsers++;
1548 xmlXPathDebugObjCounterUsers++;
1549 if (xmlXPathDebugObjCounterUsers >
1550 xmlXPathDebugObjMaxUsers)
1551 xmlXPathDebugObjMaxUsers =
1552 xmlXPathDebugObjCounterUsers;
1553 break;
1554 case XPATH_XSLT_TREE:
1555 if (! isCached)
1556 xmlXPathDebugObjTotalXSLTTree++;
1557 xmlXPathDebugObjCounterXSLTTree++;
1558 if (xmlXPathDebugObjCounterXSLTTree >
1559 xmlXPathDebugObjMaxXSLTTree)
1560 xmlXPathDebugObjMaxXSLTTree =
1561 xmlXPathDebugObjCounterXSLTTree;
1562 break;
1563 default:
1564 break;
1565 }
1566 if (! isCached)
1567 xmlXPathDebugObjTotalAll++;
1568 xmlXPathDebugObjCounterAll++;
1569 if (xmlXPathDebugObjCounterAll >
1570 xmlXPathDebugObjMaxAll)
1571 xmlXPathDebugObjMaxAll =
1572 xmlXPathDebugObjCounterAll;
1573}
1574
1575static void
1576xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1577 xmlXPathObjectType objType)
1578{
1579 int isCached = 0;
1580
1581 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001582 if (ctxt->cache != NULL) {
1583 xmlXPathContextCachePtr cache =
1584 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001585
1586 isCached = 1;
1587
1588 cache->dbgCachedAll++;
1589 switch (objType) {
1590 case XPATH_UNDEFINED:
1591 cache->dbgCachedUndefined++;
1592 break;
1593 case XPATH_NODESET:
1594 cache->dbgCachedNodeset++;
1595 break;
1596 case XPATH_BOOLEAN:
1597 cache->dbgCachedBool++;
1598 break;
1599 case XPATH_NUMBER:
1600 cache->dbgCachedNumber++;
1601 break;
1602 case XPATH_STRING:
1603 cache->dbgCachedString++;
1604 break;
1605 case XPATH_POINT:
1606 cache->dbgCachedPoint++;
1607 break;
1608 case XPATH_RANGE:
1609 cache->dbgCachedRange++;
1610 break;
1611 case XPATH_LOCATIONSET:
1612 cache->dbgCachedLocset++;
1613 break;
1614 case XPATH_USERS:
1615 cache->dbgCachedUsers++;
1616 break;
1617 case XPATH_XSLT_TREE:
1618 cache->dbgCachedXSLTTree++;
1619 break;
1620 default:
1621 break;
1622 }
1623
1624 }
1625 }
1626 switch (objType) {
1627 case XPATH_UNDEFINED:
1628 xmlXPathDebugObjCounterUndefined--;
1629 break;
1630 case XPATH_NODESET:
1631 xmlXPathDebugObjCounterNodeset--;
1632 break;
1633 case XPATH_BOOLEAN:
1634 xmlXPathDebugObjCounterBool--;
1635 break;
1636 case XPATH_NUMBER:
1637 xmlXPathDebugObjCounterNumber--;
1638 break;
1639 case XPATH_STRING:
1640 xmlXPathDebugObjCounterString--;
1641 break;
1642 case XPATH_POINT:
1643 xmlXPathDebugObjCounterPoint--;
1644 break;
1645 case XPATH_RANGE:
1646 xmlXPathDebugObjCounterRange--;
1647 break;
1648 case XPATH_LOCATIONSET:
1649 xmlXPathDebugObjCounterLocset--;
1650 break;
1651 case XPATH_USERS:
1652 xmlXPathDebugObjCounterUsers--;
1653 break;
1654 case XPATH_XSLT_TREE:
1655 xmlXPathDebugObjCounterXSLTTree--;
1656 break;
1657 default:
1658 break;
1659 }
1660 xmlXPathDebugObjCounterAll--;
1661}
1662
1663/* REVISIT TODO: Make this static when committing */
1664static void
1665xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
1666{
1667 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
1668 reqXSLTTree, reqUndefined;
1669 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
1670 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
1671 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
1672 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
1673 int leftObjs = xmlXPathDebugObjCounterAll;
1674
1675 reqAll = xmlXPathDebugObjTotalAll;
1676 reqNodeset = xmlXPathDebugObjTotalNodeset;
1677 reqString = xmlXPathDebugObjTotalString;
1678 reqBool = xmlXPathDebugObjTotalBool;
1679 reqNumber = xmlXPathDebugObjTotalNumber;
1680 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
1681 reqUndefined = xmlXPathDebugObjTotalUndefined;
1682
1683 printf("# XPath object usage:\n");
1684
1685 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001686 if (ctxt->cache != NULL) {
1687 xmlXPathContextCachePtr cache =
1688 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001689
1690 reAll = cache->dbgReusedAll;
1691 reqAll += reAll;
1692 reNodeset = cache->dbgReusedNodeset;
1693 reqNodeset += reNodeset;
1694 reString = cache->dbgReusedString;
1695 reqString += reString;
1696 reBool = cache->dbgReusedBool;
1697 reqBool += reBool;
1698 reNumber = cache->dbgReusedNumber;
1699 reqNumber += reNumber;
1700 reXSLTTree = cache->dbgReusedXSLTTree;
1701 reqXSLTTree += reXSLTTree;
1702 reUndefined = cache->dbgReusedUndefined;
1703 reqUndefined += reUndefined;
1704
1705 caAll = cache->dbgCachedAll;
1706 caBool = cache->dbgCachedBool;
1707 caNodeset = cache->dbgCachedNodeset;
1708 caString = cache->dbgCachedString;
1709 caNumber = cache->dbgCachedNumber;
1710 caXSLTTree = cache->dbgCachedXSLTTree;
1711 caUndefined = cache->dbgCachedUndefined;
1712
1713 if (cache->nodesetObjs)
1714 leftObjs -= cache->nodesetObjs->number;
1715 if (cache->stringObjs)
1716 leftObjs -= cache->stringObjs->number;
1717 if (cache->booleanObjs)
1718 leftObjs -= cache->booleanObjs->number;
1719 if (cache->numberObjs)
1720 leftObjs -= cache->numberObjs->number;
1721 if (cache->miscObjs)
1722 leftObjs -= cache->miscObjs->number;
1723 }
1724 }
1725
1726 printf("# all\n");
1727 printf("# total : %d\n", reqAll);
1728 printf("# left : %d\n", leftObjs);
1729 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
1730 printf("# reused : %d\n", reAll);
1731 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
1732
1733 printf("# node-sets\n");
1734 printf("# total : %d\n", reqNodeset);
1735 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
1736 printf("# reused : %d\n", reNodeset);
1737 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
1738
1739 printf("# strings\n");
1740 printf("# total : %d\n", reqString);
1741 printf("# created: %d\n", xmlXPathDebugObjTotalString);
1742 printf("# reused : %d\n", reString);
1743 printf("# max : %d\n", xmlXPathDebugObjMaxString);
1744
1745 printf("# booleans\n");
1746 printf("# total : %d\n", reqBool);
1747 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
1748 printf("# reused : %d\n", reBool);
1749 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
1750
1751 printf("# numbers\n");
1752 printf("# total : %d\n", reqNumber);
1753 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
1754 printf("# reused : %d\n", reNumber);
1755 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
1756
1757 printf("# XSLT result tree fragments\n");
1758 printf("# total : %d\n", reqXSLTTree);
1759 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
1760 printf("# reused : %d\n", reXSLTTree);
1761 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
1762
1763 printf("# undefined\n");
1764 printf("# total : %d\n", reqUndefined);
1765 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
1766 printf("# reused : %d\n", reUndefined);
1767 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
1768
1769}
1770
1771#endif /* XP_DEBUG_OBJ_USAGE */
1772
Daniel Veillard017b1082001-06-21 11:20:21 +00001773#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001774
1775/************************************************************************
1776 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001777 * XPath object caching *
1778 * *
1779 ************************************************************************/
1780
1781/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001782 * xmlXPathNewCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001783 *
1784 * Create a new object cache
1785 *
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001786 * Returns the xmlXPathCache just allocated.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001787 */
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001788static xmlXPathContextCachePtr
1789xmlXPathNewCache(void)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001790{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001791 xmlXPathContextCachePtr ret;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001792
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001793 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001794 if (ret == NULL) {
1795 xmlXPathErrMemory(NULL, "creating object cache\n");
1796 return(NULL);
1797 }
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001798 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001799 ret->maxNodeset = 100;
1800 ret->maxString = 100;
1801 ret->maxBoolean = 100;
1802 ret->maxNumber = 100;
1803 ret->maxMisc = 100;
1804 return(ret);
1805}
1806
1807static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001808xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001809{
1810 int i;
1811 xmlXPathObjectPtr obj;
1812
1813 if (list == NULL)
1814 return;
1815
1816 for (i = 0; i < list->number; i++) {
1817 obj = list->items[i];
1818 /*
1819 * Note that it is already assured that we don't need to
1820 * look out for namespace nodes in the node-set.
1821 */
1822 if (obj->nodesetval != NULL) {
1823 if (obj->nodesetval->nodeTab != NULL)
1824 xmlFree(obj->nodesetval->nodeTab);
1825 xmlFree(obj->nodesetval);
1826 }
1827 xmlFree(obj);
1828#ifdef XP_DEBUG_OBJ_USAGE
1829 xmlXPathDebugObjCounterAll--;
1830#endif
1831 }
1832 xmlPointerListFree(list);
1833}
1834
1835static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001836xmlXPathFreeCache(xmlXPathContextCachePtr cache)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001837{
1838 if (cache == NULL)
1839 return;
1840 if (cache->nodesetObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001841 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001842 if (cache->stringObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001843 xmlXPathCacheFreeObjectList(cache->stringObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001844 if (cache->booleanObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001845 xmlXPathCacheFreeObjectList(cache->booleanObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001846 if (cache->numberObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001847 xmlXPathCacheFreeObjectList(cache->numberObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001848 if (cache->miscObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001849 xmlXPathCacheFreeObjectList(cache->miscObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001850 xmlFree(cache);
1851}
1852
1853/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001854 * xmlXPathContextSetCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001855 *
1856 * @ctxt: the XPath context
1857 * @active: enables/disables (creates/frees) the cache
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001858 * @value: a value with semantics dependant on @options
1859 * @options: options (currently only the value 0 is used)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001860 *
1861 * Creates/frees an object cache on the XPath context.
1862 * If activates XPath objects (xmlXPathObject) will be cached internally
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001863 * to be reused.
1864 * @options:
1865 * 0: This will set the XPath object caching:
1866 * @value:
1867 * This will set the maximum number of XPath objects
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001868 * to be cached per slot
1869 * There are 5 slots for: node-set, string, number, boolean, and
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001870 * misc objects. Use <0 for the default number (100).
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001871 * Other values for @options have currently no effect.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001872 *
1873 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1874 */
1875int
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001876xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1877 int active,
1878 int value,
1879 int options)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001880{
1881 if (ctxt == NULL)
1882 return(-1);
1883 if (active) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001884 xmlXPathContextCachePtr cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001885
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001886 if (ctxt->cache == NULL) {
1887 ctxt->cache = xmlXPathNewCache();
1888 if (ctxt->cache == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001889 return(-1);
1890 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001891 cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001892 if (options == 0) {
1893 if (value < 0)
1894 value = 100;
1895 cache->maxNodeset = value;
1896 cache->maxString = value;
1897 cache->maxNumber = value;
1898 cache->maxBoolean = value;
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001899 cache->maxMisc = value;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001900 }
1901 } else if (ctxt->cache != NULL) {
1902 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1903 ctxt->cache = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001904 }
1905 return(0);
1906}
1907
1908/**
1909 * xmlXPathCacheWrapNodeSet:
1910 * @ctxt: the XPath context
1911 * @val: the NodePtr value
1912 *
1913 * This is the cached version of xmlXPathWrapNodeSet().
1914 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1915 *
1916 * Returns the created or reused object.
1917 */
1918static xmlXPathObjectPtr
1919xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
1920{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001921 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1922 xmlXPathContextCachePtr cache =
1923 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001924
1925 if ((cache->miscObjs != NULL) &&
1926 (cache->miscObjs->number != 0))
1927 {
1928 xmlXPathObjectPtr ret;
1929
1930 ret = (xmlXPathObjectPtr)
1931 cache->miscObjs->items[--cache->miscObjs->number];
1932 ret->type = XPATH_NODESET;
1933 ret->nodesetval = val;
1934#ifdef XP_DEBUG_OBJ_USAGE
1935 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
1936#endif
1937 return(ret);
1938 }
1939 }
1940
1941 return(xmlXPathWrapNodeSet(val));
1942
1943}
1944
1945/**
1946 * xmlXPathCacheWrapString:
1947 * @ctxt: the XPath context
1948 * @val: the xmlChar * value
1949 *
1950 * This is the cached version of xmlXPathWrapString().
1951 * Wraps the @val string into an XPath object.
1952 *
1953 * Returns the created or reused object.
1954 */
1955static xmlXPathObjectPtr
1956xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
1957{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001958 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1959 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001960
1961 if ((cache->stringObjs != NULL) &&
1962 (cache->stringObjs->number != 0))
1963 {
1964
1965 xmlXPathObjectPtr ret;
1966
1967 ret = (xmlXPathObjectPtr)
1968 cache->stringObjs->items[--cache->stringObjs->number];
1969 ret->type = XPATH_STRING;
1970 ret->stringval = val;
1971#ifdef XP_DEBUG_OBJ_USAGE
1972 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1973#endif
1974 return(ret);
1975 } else if ((cache->miscObjs != NULL) &&
1976 (cache->miscObjs->number != 0))
1977 {
1978 xmlXPathObjectPtr ret;
1979 /*
1980 * Fallback to misc-cache.
1981 */
1982 ret = (xmlXPathObjectPtr)
1983 cache->miscObjs->items[--cache->miscObjs->number];
1984
1985 ret->type = XPATH_STRING;
1986 ret->stringval = val;
1987#ifdef XP_DEBUG_OBJ_USAGE
1988 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1989#endif
1990 return(ret);
1991 }
1992 }
1993 return(xmlXPathWrapString(val));
1994}
1995
1996/**
1997 * xmlXPathCacheNewNodeSet:
1998 * @ctxt: the XPath context
1999 * @val: the NodePtr value
2000 *
2001 * This is the cached version of xmlXPathNewNodeSet().
2002 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2003 * it with the single Node @val
2004 *
2005 * Returns the created or reused object.
2006 */
2007static xmlXPathObjectPtr
2008xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2009{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002010 if ((ctxt != NULL) && (ctxt->cache)) {
2011 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002012
2013 if ((cache->nodesetObjs != NULL) &&
2014 (cache->nodesetObjs->number != 0))
2015 {
2016 xmlXPathObjectPtr ret;
2017 /*
2018 * Use the nodset-cache.
2019 */
2020 ret = (xmlXPathObjectPtr)
2021 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2022 ret->type = XPATH_NODESET;
2023 ret->boolval = 0;
2024 if (val) {
2025 if ((ret->nodesetval->nodeMax == 0) ||
2026 (val->type == XML_NAMESPACE_DECL))
2027 {
2028 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2029 } else {
2030 ret->nodesetval->nodeTab[0] = val;
2031 ret->nodesetval->nodeNr = 1;
2032 }
2033 }
2034#ifdef XP_DEBUG_OBJ_USAGE
2035 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2036#endif
2037 return(ret);
2038 } else if ((cache->miscObjs != NULL) &&
2039 (cache->miscObjs->number != 0))
2040 {
2041 xmlXPathObjectPtr ret;
2042 /*
2043 * Fallback to misc-cache.
2044 */
2045
2046 ret = (xmlXPathObjectPtr)
2047 cache->miscObjs->items[--cache->miscObjs->number];
2048
2049 ret->type = XPATH_NODESET;
2050 ret->boolval = 0;
2051 ret->nodesetval = xmlXPathNodeSetCreate(val);
2052#ifdef XP_DEBUG_OBJ_USAGE
2053 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2054#endif
2055 return(ret);
2056 }
2057 }
2058 return(xmlXPathNewNodeSet(val));
2059}
2060
2061/**
2062 * xmlXPathCacheNewCString:
2063 * @ctxt: the XPath context
2064 * @val: the char * value
2065 *
2066 * This is the cached version of xmlXPathNewCString().
2067 * Acquire an xmlXPathObjectPtr of type string and of value @val
2068 *
2069 * Returns the created or reused object.
2070 */
2071static xmlXPathObjectPtr
2072xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2073{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002074 if ((ctxt != NULL) && (ctxt->cache)) {
2075 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002076
2077 if ((cache->stringObjs != NULL) &&
2078 (cache->stringObjs->number != 0))
2079 {
2080 xmlXPathObjectPtr ret;
2081
2082 ret = (xmlXPathObjectPtr)
2083 cache->stringObjs->items[--cache->stringObjs->number];
2084
2085 ret->type = XPATH_STRING;
2086 ret->stringval = xmlStrdup(BAD_CAST val);
2087#ifdef XP_DEBUG_OBJ_USAGE
2088 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2089#endif
2090 return(ret);
2091 } else if ((cache->miscObjs != NULL) &&
2092 (cache->miscObjs->number != 0))
2093 {
2094 xmlXPathObjectPtr ret;
2095
2096 ret = (xmlXPathObjectPtr)
2097 cache->miscObjs->items[--cache->miscObjs->number];
2098
2099 ret->type = XPATH_STRING;
2100 ret->stringval = xmlStrdup(BAD_CAST val);
2101#ifdef XP_DEBUG_OBJ_USAGE
2102 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2103#endif
2104 return(ret);
2105 }
2106 }
2107 return(xmlXPathNewCString(val));
2108}
2109
2110/**
2111 * xmlXPathCacheNewString:
2112 * @ctxt: the XPath context
2113 * @val: the xmlChar * value
2114 *
2115 * This is the cached version of xmlXPathNewString().
2116 * Acquire an xmlXPathObjectPtr of type string and of value @val
2117 *
2118 * Returns the created or reused object.
2119 */
2120static xmlXPathObjectPtr
2121xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2122{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002123 if ((ctxt != NULL) && (ctxt->cache)) {
2124 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002125
2126 if ((cache->stringObjs != NULL) &&
2127 (cache->stringObjs->number != 0))
2128 {
2129 xmlXPathObjectPtr ret;
2130
2131 ret = (xmlXPathObjectPtr)
2132 cache->stringObjs->items[--cache->stringObjs->number];
2133 ret->type = XPATH_STRING;
2134 if (val != NULL)
2135 ret->stringval = xmlStrdup(val);
2136 else
2137 ret->stringval = xmlStrdup((const xmlChar *)"");
2138#ifdef XP_DEBUG_OBJ_USAGE
2139 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2140#endif
2141 return(ret);
2142 } else if ((cache->miscObjs != NULL) &&
2143 (cache->miscObjs->number != 0))
2144 {
2145 xmlXPathObjectPtr ret;
2146
2147 ret = (xmlXPathObjectPtr)
2148 cache->miscObjs->items[--cache->miscObjs->number];
2149
2150 ret->type = XPATH_STRING;
2151 if (val != NULL)
2152 ret->stringval = xmlStrdup(val);
2153 else
2154 ret->stringval = xmlStrdup((const xmlChar *)"");
2155#ifdef XP_DEBUG_OBJ_USAGE
2156 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2157#endif
2158 return(ret);
2159 }
2160 }
2161 return(xmlXPathNewString(val));
2162}
2163
2164/**
2165 * xmlXPathCacheNewBoolean:
2166 * @ctxt: the XPath context
2167 * @val: the boolean value
2168 *
2169 * This is the cached version of xmlXPathNewBoolean().
2170 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2171 *
2172 * Returns the created or reused object.
2173 */
2174static xmlXPathObjectPtr
2175xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2176{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002177 if ((ctxt != NULL) && (ctxt->cache)) {
2178 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002179
2180 if ((cache->booleanObjs != NULL) &&
2181 (cache->booleanObjs->number != 0))
2182 {
2183 xmlXPathObjectPtr ret;
2184
2185 ret = (xmlXPathObjectPtr)
2186 cache->booleanObjs->items[--cache->booleanObjs->number];
2187 ret->type = XPATH_BOOLEAN;
2188 ret->boolval = (val != 0);
2189#ifdef XP_DEBUG_OBJ_USAGE
2190 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2191#endif
2192 return(ret);
2193 } else if ((cache->miscObjs != NULL) &&
2194 (cache->miscObjs->number != 0))
2195 {
2196 xmlXPathObjectPtr ret;
2197
2198 ret = (xmlXPathObjectPtr)
2199 cache->miscObjs->items[--cache->miscObjs->number];
2200
2201 ret->type = XPATH_BOOLEAN;
2202 ret->boolval = (val != 0);
2203#ifdef XP_DEBUG_OBJ_USAGE
2204 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2205#endif
2206 return(ret);
2207 }
2208 }
2209 return(xmlXPathNewBoolean(val));
2210}
2211
2212/**
2213 * xmlXPathCacheNewFloat:
2214 * @ctxt: the XPath context
2215 * @val: the double value
2216 *
2217 * This is the cached version of xmlXPathNewFloat().
2218 * Acquires an xmlXPathObjectPtr of type double and of value @val
2219 *
2220 * Returns the created or reused object.
2221 */
2222static xmlXPathObjectPtr
2223xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2224{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002225 if ((ctxt != NULL) && (ctxt->cache)) {
2226 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002227
2228 if ((cache->numberObjs != NULL) &&
2229 (cache->numberObjs->number != 0))
2230 {
2231 xmlXPathObjectPtr ret;
2232
2233 ret = (xmlXPathObjectPtr)
2234 cache->numberObjs->items[--cache->numberObjs->number];
2235 ret->type = XPATH_NUMBER;
2236 ret->floatval = val;
2237#ifdef XP_DEBUG_OBJ_USAGE
2238 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2239#endif
2240 return(ret);
2241 } else if ((cache->miscObjs != NULL) &&
2242 (cache->miscObjs->number != 0))
2243 {
2244 xmlXPathObjectPtr ret;
2245
2246 ret = (xmlXPathObjectPtr)
2247 cache->miscObjs->items[--cache->miscObjs->number];
2248
2249 ret->type = XPATH_NUMBER;
2250 ret->floatval = val;
2251#ifdef XP_DEBUG_OBJ_USAGE
2252 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2253#endif
2254 return(ret);
2255 }
2256 }
2257 return(xmlXPathNewFloat(val));
2258}
2259
2260/**
2261 * xmlXPathCacheConvertString:
2262 * @ctxt: the XPath context
2263 * @val: an XPath object
2264 *
2265 * This is the cached version of xmlXPathConvertString().
2266 * Converts an existing object to its string() equivalent
2267 *
2268 * Returns a created or reused object, the old one is freed (cached)
2269 * (or the operation is done directly on @val)
2270 */
2271
2272static xmlXPathObjectPtr
2273xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2274 xmlChar *res = NULL;
2275
2276 if (val == NULL)
2277 return(xmlXPathCacheNewCString(ctxt, ""));
2278
2279 switch (val->type) {
2280 case XPATH_UNDEFINED:
2281#ifdef DEBUG_EXPR
2282 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2283#endif
2284 break;
2285 case XPATH_NODESET:
2286 case XPATH_XSLT_TREE:
2287 res = xmlXPathCastNodeSetToString(val->nodesetval);
2288 break;
2289 case XPATH_STRING:
2290 return(val);
2291 case XPATH_BOOLEAN:
2292 res = xmlXPathCastBooleanToString(val->boolval);
2293 break;
2294 case XPATH_NUMBER:
2295 res = xmlXPathCastNumberToString(val->floatval);
2296 break;
2297 case XPATH_USERS:
2298 case XPATH_POINT:
2299 case XPATH_RANGE:
2300 case XPATH_LOCATIONSET:
2301 TODO;
2302 break;
2303 }
2304 xmlXPathReleaseObject(ctxt, val);
2305 if (res == NULL)
2306 return(xmlXPathCacheNewCString(ctxt, ""));
2307 return(xmlXPathCacheWrapString(ctxt, res));
2308}
2309
2310/**
2311 * xmlXPathCacheObjectCopy:
2312 * @ctxt: the XPath context
2313 * @val: the original object
2314 *
2315 * This is the cached version of xmlXPathObjectCopy().
2316 * Acquire a copy of a given object
2317 *
2318 * Returns a created or reused created object.
2319 */
2320static xmlXPathObjectPtr
2321xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2322{
2323 if (val == NULL)
2324 return(NULL);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002325
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002326 if (XP_HAS_CACHE(ctxt)) {
2327 switch (val->type) {
2328 case XPATH_NODESET:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002329 return(xmlXPathCacheWrapNodeSet(ctxt,
2330 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002331 case XPATH_STRING:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002332 return(xmlXPathCacheNewString(ctxt, val->stringval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002333 case XPATH_BOOLEAN:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002334 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002335 case XPATH_NUMBER:
2336 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2337 default:
2338 break;
2339 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002340 }
2341 return(xmlXPathObjectCopy(val));
2342}
2343
2344/**
2345 * xmlXPathCacheConvertBoolean:
2346 * @ctxt: the XPath context
2347 * @val: an XPath object
2348 *
2349 * This is the cached version of xmlXPathConvertBoolean().
2350 * Converts an existing object to its boolean() equivalent
2351 *
2352 * Returns a created or reused object, the old one is freed (or the operation
2353 * is done directly on @val)
2354 */
2355static xmlXPathObjectPtr
2356xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2357 xmlXPathObjectPtr ret;
2358
2359 if (val == NULL)
2360 return(xmlXPathCacheNewBoolean(ctxt, 0));
2361 if (val->type == XPATH_BOOLEAN)
2362 return(val);
2363 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2364 xmlXPathReleaseObject(ctxt, val);
2365 return(ret);
2366}
2367
2368/**
2369 * xmlXPathCacheConvertNumber:
2370 * @ctxt: the XPath context
2371 * @val: an XPath object
2372 *
2373 * This is the cached version of xmlXPathConvertNumber().
2374 * Converts an existing object to its number() equivalent
2375 *
2376 * Returns a created or reused object, the old one is freed (or the operation
2377 * is done directly on @val)
2378 */
2379static xmlXPathObjectPtr
2380xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2381 xmlXPathObjectPtr ret;
2382
2383 if (val == NULL)
2384 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2385 if (val->type == XPATH_NUMBER)
2386 return(val);
2387 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2388 xmlXPathReleaseObject(ctxt, val);
2389 return(ret);
2390}
2391
2392/************************************************************************
2393 * *
Owen Taylor3473f882001-02-23 17:55:21 +00002394 * Parser stacks related functions and macros *
2395 * *
2396 ************************************************************************/
2397
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002398/**
2399 * valuePop:
2400 * @ctxt: an XPath evaluation context
2401 *
2402 * Pops the top XPath object from the value stack
2403 *
2404 * Returns the XPath object just removed
2405 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002406xmlXPathObjectPtr
Daniel Veillard1c732d22002-11-30 11:22:59 +00002407valuePop(xmlXPathParserContextPtr ctxt)
2408{
2409 xmlXPathObjectPtr ret;
2410
Daniel Veillarda82b1822004-11-08 16:24:57 +00002411 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
Daniel Veillard24505b02005-07-28 23:49:35 +00002412 return (NULL);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002413 ctxt->valueNr--;
2414 if (ctxt->valueNr > 0)
2415 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2416 else
2417 ctxt->value = NULL;
2418 ret = ctxt->valueTab[ctxt->valueNr];
Daniel Veillard24505b02005-07-28 23:49:35 +00002419 ctxt->valueTab[ctxt->valueNr] = NULL;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002420 return (ret);
2421}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002422/**
2423 * valuePush:
2424 * @ctxt: an XPath evaluation context
2425 * @value: the XPath object
2426 *
2427 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002428 *
2429 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002430 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002431int
Daniel Veillard1c732d22002-11-30 11:22:59 +00002432valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2433{
Daniel Veillarda82b1822004-11-08 16:24:57 +00002434 if ((ctxt == NULL) || (value == NULL)) return(-1);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002435 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002436 xmlXPathObjectPtr *tmp;
2437
2438 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2439 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00002440 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002441 if (tmp == NULL) {
Daniel Veillard1c732d22002-11-30 11:22:59 +00002442 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
2443 return (0);
2444 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002445 ctxt->valueMax *= 2;
2446 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002447 }
2448 ctxt->valueTab[ctxt->valueNr] = value;
2449 ctxt->value = value;
2450 return (ctxt->valueNr++);
2451}
Owen Taylor3473f882001-02-23 17:55:21 +00002452
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002453/**
2454 * xmlXPathPopBoolean:
2455 * @ctxt: an XPath parser context
2456 *
2457 * Pops a boolean from the stack, handling conversion if needed.
2458 * Check error with #xmlXPathCheckError.
2459 *
2460 * Returns the boolean
2461 */
2462int
2463xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2464 xmlXPathObjectPtr obj;
2465 int ret;
2466
2467 obj = valuePop(ctxt);
2468 if (obj == NULL) {
2469 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2470 return(0);
2471 }
William M. Brack08171912003-12-29 02:52:11 +00002472 if (obj->type != XPATH_BOOLEAN)
2473 ret = xmlXPathCastToBoolean(obj);
2474 else
2475 ret = obj->boolval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002476 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002477 return(ret);
2478}
2479
2480/**
2481 * xmlXPathPopNumber:
2482 * @ctxt: an XPath parser context
2483 *
2484 * Pops a number from the stack, handling conversion if needed.
2485 * Check error with #xmlXPathCheckError.
2486 *
2487 * Returns the number
2488 */
2489double
2490xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2491 xmlXPathObjectPtr obj;
2492 double ret;
2493
2494 obj = valuePop(ctxt);
2495 if (obj == NULL) {
2496 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2497 return(0);
2498 }
William M. Brack08171912003-12-29 02:52:11 +00002499 if (obj->type != XPATH_NUMBER)
2500 ret = xmlXPathCastToNumber(obj);
2501 else
2502 ret = obj->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002503 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002504 return(ret);
2505}
2506
2507/**
2508 * xmlXPathPopString:
2509 * @ctxt: an XPath parser context
2510 *
2511 * Pops a string from the stack, handling conversion if needed.
2512 * Check error with #xmlXPathCheckError.
2513 *
2514 * Returns the string
2515 */
2516xmlChar *
2517xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2518 xmlXPathObjectPtr obj;
2519 xmlChar * ret;
2520
2521 obj = valuePop(ctxt);
2522 if (obj == NULL) {
2523 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2524 return(NULL);
2525 }
William M. Brack08171912003-12-29 02:52:11 +00002526 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002527 /* TODO: needs refactoring somewhere else */
2528 if (obj->stringval == ret)
2529 obj->stringval = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002530 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002531 return(ret);
2532}
2533
2534/**
2535 * xmlXPathPopNodeSet:
2536 * @ctxt: an XPath parser context
2537 *
2538 * Pops a node-set from the stack, handling conversion if needed.
2539 * Check error with #xmlXPathCheckError.
2540 *
2541 * Returns the node-set
2542 */
2543xmlNodeSetPtr
2544xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2545 xmlXPathObjectPtr obj;
2546 xmlNodeSetPtr ret;
2547
Daniel Veillardf2a36f92004-11-08 17:55:01 +00002548 if (ctxt == NULL) return(NULL);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002549 if (ctxt->value == NULL) {
2550 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2551 return(NULL);
2552 }
2553 if (!xmlXPathStackIsNodeSet(ctxt)) {
2554 xmlXPathSetTypeError(ctxt);
2555 return(NULL);
2556 }
2557 obj = valuePop(ctxt);
2558 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00002559#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00002560 /* to fix memory leak of not clearing obj->user */
2561 if (obj->boolval && obj->user != NULL)
2562 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00002563#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002564 obj->nodesetval = NULL;
2565 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002566 return(ret);
2567}
2568
2569/**
2570 * xmlXPathPopExternal:
2571 * @ctxt: an XPath parser context
2572 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002573 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002574 * Check error with #xmlXPathCheckError.
2575 *
2576 * Returns the object
2577 */
2578void *
2579xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2580 xmlXPathObjectPtr obj;
2581 void * ret;
2582
Daniel Veillarda82b1822004-11-08 16:24:57 +00002583 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002584 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2585 return(NULL);
2586 }
2587 if (ctxt->value->type != XPATH_USERS) {
2588 xmlXPathSetTypeError(ctxt);
2589 return(NULL);
2590 }
2591 obj = valuePop(ctxt);
2592 ret = obj->user;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002593 obj->user = NULL;
2594 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002595 return(ret);
2596}
2597
Owen Taylor3473f882001-02-23 17:55:21 +00002598/*
2599 * Macros for accessing the content. Those should be used only by the parser,
2600 * and not exported.
2601 *
2602 * Dirty macros, i.e. one need to make assumption on the context to use them
2603 *
2604 * CUR_PTR return the current pointer to the xmlChar to be parsed.
2605 * CUR returns the current xmlChar value, i.e. a 8 bit value
2606 * in ISO-Latin or UTF-8.
2607 * This should be used internally by the parser
2608 * only to compare to ASCII values otherwise it would break when
2609 * running with UTF-8 encoding.
2610 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
2611 * to compare on ASCII based substring.
2612 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2613 * strings within the parser.
2614 * CURRENT Returns the current char value, with the full decoding of
2615 * UTF-8 if we are using this mode. It returns an int.
2616 * NEXT Skip to the next character, this does the proper decoding
2617 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
2618 * It returns the pointer to the current xmlChar.
2619 */
2620
2621#define CUR (*ctxt->cur)
2622#define SKIP(val) ctxt->cur += (val)
2623#define NXT(val) ctxt->cur[(val)]
2624#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00002625#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2626
2627#define COPY_BUF(l,b,i,v) \
2628 if (l == 1) b[i++] = (xmlChar) v; \
2629 else i += xmlCopyChar(l,&b[i],v)
2630
2631#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00002632
2633#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00002634 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00002635
2636#define CURRENT (*ctxt->cur)
2637#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
2638
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002639
2640#ifndef DBL_DIG
2641#define DBL_DIG 16
2642#endif
2643#ifndef DBL_EPSILON
2644#define DBL_EPSILON 1E-9
2645#endif
2646
2647#define UPPER_DOUBLE 1E9
2648#define LOWER_DOUBLE 1E-5
2649
2650#define INTEGER_DIGITS DBL_DIG
2651#define FRACTION_DIGITS (DBL_DIG + 1)
2652#define EXPONENT_DIGITS (3 + 2)
2653
2654/**
2655 * xmlXPathFormatNumber:
2656 * @number: number to format
2657 * @buffer: output buffer
2658 * @buffersize: size of output buffer
2659 *
2660 * Convert the number into a string representation.
2661 */
2662static void
2663xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2664{
Daniel Veillardcda96922001-08-21 10:56:31 +00002665 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002666 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00002667 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002668 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002669 break;
2670 case -1:
2671 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002672 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002673 break;
2674 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00002675 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002676 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002677 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00002678 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002679 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002680 } else if (number == ((int) number)) {
2681 char work[30];
2682 char *ptr, *cur;
Daniel Veillardb3d14912005-09-04 20:47:39 +00002683 int value = (int) number;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002684
2685 ptr = &buffer[0];
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002686 if (value == 0) {
2687 *ptr++ = '0';
2688 } else {
Daniel Veillardb3d14912005-09-04 20:47:39 +00002689 snprintf(work, 29, "%d", value);
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002690 cur = &work[0];
Daniel Veillardb3d14912005-09-04 20:47:39 +00002691 while ((*cur) && (ptr - buffer < buffersize)) {
2692 *ptr++ = *cur++;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002693 }
2694 }
2695 if (ptr - buffer < buffersize) {
2696 *ptr = 0;
2697 } else if (buffersize > 0) {
2698 ptr--;
2699 *ptr = 0;
2700 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002701 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002702 /* 3 is sign, decimal point, and terminating zero */
2703 char work[DBL_DIG + EXPONENT_DIGITS + 3];
2704 int integer_place, fraction_place;
2705 char *ptr;
2706 char *after_fraction;
2707 double absolute_value;
2708 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002709
Bjorn Reese70a9da52001-04-21 16:57:29 +00002710 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002711
Bjorn Reese70a9da52001-04-21 16:57:29 +00002712 /*
2713 * First choose format - scientific or regular floating point.
2714 * In either case, result is in work, and after_fraction points
2715 * just past the fractional part.
2716 */
2717 if ( ((absolute_value > UPPER_DOUBLE) ||
2718 (absolute_value < LOWER_DOUBLE)) &&
2719 (absolute_value != 0.0) ) {
2720 /* Use scientific notation */
2721 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2722 fraction_place = DBL_DIG - 1;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002723 size = snprintf(work, sizeof(work),"%*.*e",
Bjorn Reese70a9da52001-04-21 16:57:29 +00002724 integer_place, fraction_place, number);
Daniel Veillard11ce4002006-03-10 00:36:23 +00002725 while ((size > 0) && (work[size] != 'e')) size--;
2726 after_fraction = work + size;
2727
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002728 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002729 else {
2730 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00002731 if (absolute_value > 0.0)
2732 integer_place = 1 + (int)log10(absolute_value);
2733 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00002734 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002735 fraction_place = (integer_place > 0)
2736 ? DBL_DIG - integer_place
2737 : DBL_DIG;
2738 size = snprintf(work, sizeof(work), "%0.*f",
2739 fraction_place, number);
2740 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002741 }
2742
Bjorn Reese70a9da52001-04-21 16:57:29 +00002743 /* Remove fractional trailing zeroes */
2744 ptr = after_fraction;
2745 while (*(--ptr) == '0')
2746 ;
2747 if (*ptr != '.')
2748 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002749 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002750
2751 /* Finally copy result back to caller */
2752 size = strlen(work) + 1;
2753 if (size > buffersize) {
2754 work[buffersize - 1] = 0;
2755 size = buffersize;
2756 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002757 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002758 }
2759 break;
2760 }
2761}
2762
Owen Taylor3473f882001-02-23 17:55:21 +00002763
2764/************************************************************************
2765 * *
2766 * Routines to handle NodeSets *
2767 * *
2768 ************************************************************************/
2769
2770/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002771 * xmlXPathOrderDocElems:
2772 * @doc: an input document
2773 *
2774 * Call this routine to speed up XPath computation on static documents.
2775 * This stamps all the element nodes with the document order
2776 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00002777 * field, the value stored is actually - the node number (starting at -1)
2778 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002779 *
William M. Brack08171912003-12-29 02:52:11 +00002780 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002781 * of error.
2782 */
2783long
2784xmlXPathOrderDocElems(xmlDocPtr doc) {
2785 long count = 0;
2786 xmlNodePtr cur;
2787
2788 if (doc == NULL)
2789 return(-1);
2790 cur = doc->children;
2791 while (cur != NULL) {
2792 if (cur->type == XML_ELEMENT_NODE) {
2793 cur->content = (void *) (-(++count));
2794 if (cur->children != NULL) {
2795 cur = cur->children;
2796 continue;
2797 }
2798 }
2799 if (cur->next != NULL) {
2800 cur = cur->next;
2801 continue;
2802 }
2803 do {
2804 cur = cur->parent;
2805 if (cur == NULL)
2806 break;
2807 if (cur == (xmlNodePtr) doc) {
2808 cur = NULL;
2809 break;
2810 }
2811 if (cur->next != NULL) {
2812 cur = cur->next;
2813 break;
2814 }
2815 } while (cur != NULL);
2816 }
2817 return(count);
2818}
2819
2820/**
Owen Taylor3473f882001-02-23 17:55:21 +00002821 * xmlXPathCmpNodes:
2822 * @node1: the first node
2823 * @node2: the second node
2824 *
2825 * Compare two nodes w.r.t document order
2826 *
2827 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00002828 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00002829 */
2830int
2831xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2832 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002833 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002834 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002835 xmlNodePtr cur, root;
2836
2837 if ((node1 == NULL) || (node2 == NULL))
2838 return(-2);
2839 /*
2840 * a couple of optimizations which will avoid computations in most cases
2841 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00002842 if (node1->type == XML_ATTRIBUTE_NODE) {
2843 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002844 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002845 node1 = node1->parent;
2846 }
2847 if (node2->type == XML_ATTRIBUTE_NODE) {
2848 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002849 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002850 node2 = node2->parent;
2851 }
2852 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00002853 if (attr1 == attr2) {
2854 /* not required, but we keep attributes in order */
2855 if (attr1 != 0) {
2856 cur = attrNode2->prev;
2857 while (cur != NULL) {
2858 if (cur == attrNode1)
2859 return (1);
2860 cur = cur->prev;
2861 }
2862 return (-1);
2863 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00002864 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00002865 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00002866 if (attr2 == 1)
2867 return(1);
2868 return(-1);
2869 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002870 if ((node1->type == XML_NAMESPACE_DECL) ||
2871 (node2->type == XML_NAMESPACE_DECL))
2872 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00002873 if (node1 == node2->prev)
2874 return(1);
2875 if (node1 == node2->next)
2876 return(-1);
2877
2878 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002879 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002880 */
2881 if ((node1->type == XML_ELEMENT_NODE) &&
2882 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002883 (0 > (long) node1->content) &&
2884 (0 > (long) node2->content) &&
2885 (node1->doc == node2->doc)) {
2886 long l1, l2;
2887
2888 l1 = -((long) node1->content);
2889 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002890 if (l1 < l2)
2891 return(1);
2892 if (l1 > l2)
2893 return(-1);
2894 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002895
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002896 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002897 * compute depth to root
2898 */
2899 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2900 if (cur == node1)
2901 return(1);
2902 depth2++;
2903 }
2904 root = cur;
2905 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2906 if (cur == node2)
2907 return(-1);
2908 depth1++;
2909 }
2910 /*
2911 * Distinct document (or distinct entities :-( ) case.
2912 */
2913 if (root != cur) {
2914 return(-2);
2915 }
2916 /*
2917 * get the nearest common ancestor.
2918 */
2919 while (depth1 > depth2) {
2920 depth1--;
2921 node1 = node1->parent;
2922 }
2923 while (depth2 > depth1) {
2924 depth2--;
2925 node2 = node2->parent;
2926 }
2927 while (node1->parent != node2->parent) {
2928 node1 = node1->parent;
2929 node2 = node2->parent;
2930 /* should not happen but just in case ... */
2931 if ((node1 == NULL) || (node2 == NULL))
2932 return(-2);
2933 }
2934 /*
2935 * Find who's first.
2936 */
Daniel Veillardf49be472004-02-17 11:48:18 +00002937 if (node1 == node2->prev)
2938 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00002939 if (node1 == node2->next)
2940 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00002941 /*
2942 * Speedup using document order if availble.
2943 */
2944 if ((node1->type == XML_ELEMENT_NODE) &&
2945 (node2->type == XML_ELEMENT_NODE) &&
2946 (0 > (long) node1->content) &&
2947 (0 > (long) node2->content) &&
2948 (node1->doc == node2->doc)) {
2949 long l1, l2;
2950
2951 l1 = -((long) node1->content);
2952 l2 = -((long) node2->content);
2953 if (l1 < l2)
2954 return(1);
2955 if (l1 > l2)
2956 return(-1);
2957 }
2958
Owen Taylor3473f882001-02-23 17:55:21 +00002959 for (cur = node1->next;cur != NULL;cur = cur->next)
2960 if (cur == node2)
2961 return(1);
2962 return(-1); /* assume there is no sibling list corruption */
2963}
2964
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00002965#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002966/**
2967 * xmlXPathCmpNodesExt:
2968 * @node1: the first node
2969 * @node2: the second node
2970 *
2971 * Compare two nodes w.r.t document order.
2972 * This one is optimized for handling of non-element nodes.
2973 *
2974 * Returns -2 in case of error 1 if first point < second point, 0 if
2975 * it's the same node, -1 otherwise
2976 */
2977static int
2978xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
2979 int depth1, depth2;
2980 int misc = 0, precedence1 = 0, precedence2 = 0;
2981 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
2982 xmlNodePtr cur, root;
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00002983 long l1, l2;
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002984
2985 if ((node1 == NULL) || (node2 == NULL))
2986 return(-2);
2987
2988 if (node1 == node2)
2989 return(0);
2990
2991 /*
2992 * a couple of optimizations which will avoid computations in most cases
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00002993 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002994 switch (node1->type) {
2995 case XML_ELEMENT_NODE:
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00002996 if (node2->type == XML_ELEMENT_NODE) {
2997 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
2998 (0 > (long) node2->content) &&
2999 (node1->doc == node2->doc))
3000 {
3001 l1 = -((long) node1->content);
3002 l2 = -((long) node2->content);
3003 if (l1 < l2)
3004 return(1);
3005 if (l1 > l2)
3006 return(-1);
3007 } else
3008 goto turtle_comparison;
3009 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003010 break;
3011 case XML_ATTRIBUTE_NODE:
3012 precedence1 = 1; /* element is owner */
3013 miscNode1 = node1;
3014 node1 = node1->parent;
3015 misc = 1;
3016 break;
3017 case XML_TEXT_NODE:
3018 case XML_CDATA_SECTION_NODE:
3019 case XML_COMMENT_NODE:
3020 case XML_PI_NODE: {
3021 miscNode1 = node1;
3022 /*
3023 * Find nearest element node.
3024 */
3025 if (node1->prev != NULL) {
3026 do {
3027 node1 = node1->prev;
3028 if (node1->type == XML_ELEMENT_NODE) {
3029 precedence1 = 3; /* element in prev-sibl axis */
3030 break;
3031 }
3032 if (node1->prev == NULL) {
3033 precedence1 = 2; /* element is parent */
3034 /*
3035 * URGENT TODO: Are there any cases, where the
3036 * parent of such a node is not an element node?
3037 */
3038 node1 = node1->parent;
3039 break;
3040 }
3041 } while (1);
3042 } else {
3043 precedence1 = 2; /* element is parent */
3044 node1 = node1->parent;
3045 }
3046 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE)) {
3047 /*
3048 * Fallback for whatever case.
3049 */
3050 node1 = miscNode1;
3051 precedence1 = 0;
3052 } else
3053 misc = 1;
3054 }
3055 break;
3056 case XML_NAMESPACE_DECL:
3057 /*
3058 * TODO: why do we return 1 for namespace nodes?
3059 */
3060 return(1);
3061 default:
3062 break;
3063 }
3064 switch (node2->type) {
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003065 case XML_ELEMENT_NODE:
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003066 break;
3067 case XML_ATTRIBUTE_NODE:
3068 precedence2 = 1; /* element is owner */
3069 miscNode2 = node2;
3070 node2 = node2->parent;
3071 misc = 1;
3072 break;
3073 case XML_TEXT_NODE:
3074 case XML_CDATA_SECTION_NODE:
3075 case XML_COMMENT_NODE:
3076 case XML_PI_NODE: {
3077 miscNode2 = node2;
3078 if (node2->prev != NULL) {
3079 do {
3080 node2 = node2->prev;
3081 if (node2->type == XML_ELEMENT_NODE) {
3082 precedence2 = 3; /* element in prev-sibl axis */
3083 break;
3084 }
3085 if (node2->prev == NULL) {
3086 precedence2 = 2; /* element is parent */
3087 node2 = node2->parent;
3088 break;
3089 }
3090 } while (1);
3091 } else {
3092 precedence2 = 2; /* element is parent */
3093 node2 = node2->parent;
3094 }
3095 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3096 (0 <= (long) node1->content))
3097 {
3098 node2 = miscNode2;
3099 precedence2 = 0;
3100 } else
3101 misc = 1;
3102 }
3103 break;
3104 case XML_NAMESPACE_DECL:
3105 return(1);
3106 default:
3107 break;
3108 }
3109 if (misc) {
3110 if (node1 == node2) {
3111 if (precedence1 == precedence2) {
3112 /*
3113 * The ugly case; but normally there aren't many
3114 * adjacent non-element nodes around.
3115 */
3116 cur = miscNode2->prev;
3117 while (cur != NULL) {
3118 if (cur == miscNode1)
3119 return(1);
3120 if (cur->type == XML_ELEMENT_NODE)
3121 return(-1);
3122 cur = cur->prev;
3123 }
3124 return (-1);
3125 } else {
3126 /*
3127 * Evaluate based on higher precedence wrt to the element.
3128 * TODO: This assumes attributes are sorted before content.
3129 * Is this 100% correct?
3130 */
3131 if (precedence1 < precedence2)
3132 return(1);
3133 else
3134 return(-1);
3135 }
3136 }
3137 /*
3138 * Special case: One of the helper-elements is contained by the other.
3139 * <foo>
3140 * <node2>
3141 * <node1>Text-1(precedence1 == 2)</node1>
3142 * </node2>
3143 * Text-6(precedence2 == 3)
3144 * </foo>
3145 */
3146 if ((precedence2 == 3) && (precedence1 > 1)) {
3147 cur = node1->parent;
3148 while (cur) {
3149 if (cur == node2)
3150 return(1);
3151 cur = cur->parent;
3152 }
3153 }
3154 if ((precedence1 == 3) && (precedence2 > 1)) {
3155 cur = node2->parent;
3156 while (cur) {
3157 if (cur == node1)
3158 return(-1);
3159 cur = cur->parent;
3160 }
3161 }
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003162 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003163
3164 /*
3165 * Speedup using document order if availble.
3166 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003167 if ((node1->type == XML_ELEMENT_NODE) &&
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003168 (node2->type == XML_ELEMENT_NODE) &&
3169 (0 > (long) node1->content) &&
3170 (0 > (long) node2->content) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003171 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003172
3173 l1 = -((long) node1->content);
3174 l2 = -((long) node2->content);
3175 if (l1 < l2)
3176 return(1);
3177 if (l1 > l2)
3178 return(-1);
3179 }
3180
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003181turtle_comparison:
3182
3183 if (node1 == node2->prev)
3184 return(1);
3185 if (node1 == node2->next)
3186 return(-1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003187 /*
3188 * compute depth to root
3189 */
3190 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3191 if (cur == node1)
3192 return(1);
3193 depth2++;
3194 }
3195 root = cur;
3196 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3197 if (cur == node2)
3198 return(-1);
3199 depth1++;
3200 }
3201 /*
3202 * Distinct document (or distinct entities :-( ) case.
3203 */
3204 if (root != cur) {
3205 return(-2);
3206 }
3207 /*
3208 * get the nearest common ancestor.
3209 */
3210 while (depth1 > depth2) {
3211 depth1--;
3212 node1 = node1->parent;
3213 }
3214 while (depth2 > depth1) {
3215 depth2--;
3216 node2 = node2->parent;
3217 }
3218 while (node1->parent != node2->parent) {
3219 node1 = node1->parent;
3220 node2 = node2->parent;
3221 /* should not happen but just in case ... */
3222 if ((node1 == NULL) || (node2 == NULL))
3223 return(-2);
3224 }
3225 /*
3226 * Find who's first.
3227 */
3228 if (node1 == node2->prev)
3229 return(1);
3230 if (node1 == node2->next)
3231 return(-1);
3232 /*
3233 * Speedup using document order if availble.
3234 */
3235 if ((node1->type == XML_ELEMENT_NODE) &&
3236 (node2->type == XML_ELEMENT_NODE) &&
3237 (0 > (long) node1->content) &&
3238 (0 > (long) node2->content) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003239 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003240
3241 l1 = -((long) node1->content);
3242 l2 = -((long) node2->content);
3243 if (l1 < l2)
3244 return(1);
3245 if (l1 > l2)
3246 return(-1);
3247 }
3248
3249 for (cur = node1->next;cur != NULL;cur = cur->next)
3250 if (cur == node2)
3251 return(1);
3252 return(-1); /* assume there is no sibling list corruption */
3253}
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003254#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003255
Owen Taylor3473f882001-02-23 17:55:21 +00003256/**
3257 * xmlXPathNodeSetSort:
3258 * @set: the node set
3259 *
3260 * Sort the node set in document order
3261 */
3262void
3263xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003264 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003265 xmlNodePtr tmp;
3266
3267 if (set == NULL)
3268 return;
3269
3270 /* Use Shell's sort to sort the node-set */
3271 len = set->nodeNr;
3272 for (incr = len / 2; incr > 0; incr /= 2) {
3273 for (i = incr; i < len; i++) {
3274 j = i - incr;
3275 while (j >= 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003276#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003277 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3278 set->nodeTab[j + incr]) == -1)
3279#else
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003280 if (xmlXPathCmpNodes(set->nodeTab[j],
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003281 set->nodeTab[j + incr]) == -1)
3282#endif
3283 {
Owen Taylor3473f882001-02-23 17:55:21 +00003284 tmp = set->nodeTab[j];
3285 set->nodeTab[j] = set->nodeTab[j + incr];
3286 set->nodeTab[j + incr] = tmp;
3287 j -= incr;
3288 } else
3289 break;
3290 }
3291 }
3292 }
3293}
3294
3295#define XML_NODESET_DEFAULT 10
3296/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003297 * xmlXPathNodeSetDupNs:
3298 * @node: the parent node of the namespace XPath node
3299 * @ns: the libxml namespace declaration node.
3300 *
3301 * Namespace node in libxml don't match the XPath semantic. In a node set
3302 * the namespace nodes are duplicated and the next pointer is set to the
3303 * parent node in the XPath semantic.
3304 *
3305 * Returns the newly created object.
3306 */
3307static xmlNodePtr
3308xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3309 xmlNsPtr cur;
3310
3311 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3312 return(NULL);
3313 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3314 return((xmlNodePtr) ns);
3315
3316 /*
3317 * Allocate a new Namespace and fill the fields.
3318 */
3319 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3320 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003321 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003322 return(NULL);
3323 }
3324 memset(cur, 0, sizeof(xmlNs));
3325 cur->type = XML_NAMESPACE_DECL;
3326 if (ns->href != NULL)
3327 cur->href = xmlStrdup(ns->href);
3328 if (ns->prefix != NULL)
3329 cur->prefix = xmlStrdup(ns->prefix);
3330 cur->next = (xmlNsPtr) node;
3331 return((xmlNodePtr) cur);
3332}
3333
3334/**
3335 * xmlXPathNodeSetFreeNs:
3336 * @ns: the XPath namespace node found in a nodeset.
3337 *
William M. Brack08171912003-12-29 02:52:11 +00003338 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003339 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00003340 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003341 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00003342void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003343xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3344 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3345 return;
3346
3347 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3348 if (ns->href != NULL)
3349 xmlFree((xmlChar *)ns->href);
3350 if (ns->prefix != NULL)
3351 xmlFree((xmlChar *)ns->prefix);
3352 xmlFree(ns);
3353 }
3354}
3355
3356/**
Owen Taylor3473f882001-02-23 17:55:21 +00003357 * xmlXPathNodeSetCreate:
3358 * @val: an initial xmlNodePtr, or NULL
3359 *
3360 * Create a new xmlNodeSetPtr of type double and of value @val
3361 *
3362 * Returns the newly created object.
3363 */
3364xmlNodeSetPtr
3365xmlXPathNodeSetCreate(xmlNodePtr val) {
3366 xmlNodeSetPtr ret;
3367
3368 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3369 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003370 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003371 return(NULL);
3372 }
3373 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3374 if (val != NULL) {
3375 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3376 sizeof(xmlNodePtr));
3377 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003378 xmlXPathErrMemory(NULL, "creating nodeset\n");
3379 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003380 return(NULL);
3381 }
3382 memset(ret->nodeTab, 0 ,
3383 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3384 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003385 if (val->type == XML_NAMESPACE_DECL) {
3386 xmlNsPtr ns = (xmlNsPtr) val;
3387
3388 ret->nodeTab[ret->nodeNr++] =
3389 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3390 } else
3391 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003392 }
3393 return(ret);
3394}
3395
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003396/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003397 * xmlXPathNodeSetCreateSize:
3398 * @size: the initial size of the set
3399 *
3400 * Create a new xmlNodeSetPtr of type double and of value @val
3401 *
3402 * Returns the newly created object.
3403 */
3404static xmlNodeSetPtr
3405xmlXPathNodeSetCreateSize(int size) {
3406 xmlNodeSetPtr ret;
3407
3408 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3409 if (ret == NULL) {
3410 xmlXPathErrMemory(NULL, "creating nodeset\n");
3411 return(NULL);
3412 }
3413 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3414 if (size < XML_NODESET_DEFAULT)
3415 size = XML_NODESET_DEFAULT;
3416 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3417 if (ret->nodeTab == NULL) {
3418 xmlXPathErrMemory(NULL, "creating nodeset\n");
3419 xmlFree(ret);
3420 return(NULL);
3421 }
3422 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3423 ret->nodeMax = size;
3424 return(ret);
3425}
3426
3427/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003428 * xmlXPathNodeSetContains:
3429 * @cur: the node-set
3430 * @val: the node
3431 *
3432 * checks whether @cur contains @val
3433 *
3434 * Returns true (1) if @cur contains @val, false (0) otherwise
3435 */
3436int
3437xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3438 int i;
3439
Daniel Veillarda82b1822004-11-08 16:24:57 +00003440 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003441 if (val->type == XML_NAMESPACE_DECL) {
3442 for (i = 0; i < cur->nodeNr; i++) {
3443 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3444 xmlNsPtr ns1, ns2;
3445
3446 ns1 = (xmlNsPtr) val;
3447 ns2 = (xmlNsPtr) cur->nodeTab[i];
3448 if (ns1 == ns2)
3449 return(1);
3450 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3451 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3452 return(1);
3453 }
3454 }
3455 } else {
3456 for (i = 0; i < cur->nodeNr; i++) {
3457 if (cur->nodeTab[i] == val)
3458 return(1);
3459 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003460 }
3461 return(0);
3462}
3463
3464/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003465 * xmlXPathNodeSetAddNs:
3466 * @cur: the initial node set
3467 * @node: the hosting node
3468 * @ns: a the namespace node
3469 *
3470 * add a new namespace node to an existing NodeSet
3471 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00003472void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003473xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3474 int i;
3475
Daniel Veillarda82b1822004-11-08 16:24:57 +00003476
3477 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3478 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003479 (node->type != XML_ELEMENT_NODE))
3480 return;
3481
William M. Brack08171912003-12-29 02:52:11 +00003482 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003483 /*
William M. Brack08171912003-12-29 02:52:11 +00003484 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003485 */
3486 for (i = 0;i < cur->nodeNr;i++) {
3487 if ((cur->nodeTab[i] != NULL) &&
3488 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00003489 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003490 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3491 return;
3492 }
3493
3494 /*
3495 * grow the nodeTab if needed
3496 */
3497 if (cur->nodeMax == 0) {
3498 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3499 sizeof(xmlNodePtr));
3500 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003501 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003502 return;
3503 }
3504 memset(cur->nodeTab, 0 ,
3505 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3506 cur->nodeMax = XML_NODESET_DEFAULT;
3507 } else if (cur->nodeNr == cur->nodeMax) {
3508 xmlNodePtr *temp;
3509
3510 cur->nodeMax *= 2;
3511 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3512 sizeof(xmlNodePtr));
3513 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003514 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003515 return;
3516 }
3517 cur->nodeTab = temp;
3518 }
3519 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3520}
3521
3522/**
Owen Taylor3473f882001-02-23 17:55:21 +00003523 * xmlXPathNodeSetAdd:
3524 * @cur: the initial node set
3525 * @val: a new xmlNodePtr
3526 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003527 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00003528 */
3529void
3530xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3531 int i;
3532
Daniel Veillarda82b1822004-11-08 16:24:57 +00003533 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003534
Daniel Veillardef0b4502003-03-24 13:57:34 +00003535#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00003536 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3537 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00003538#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00003539
William M. Brack08171912003-12-29 02:52:11 +00003540 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003541 /*
William M. Brack08171912003-12-29 02:52:11 +00003542 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00003543 */
3544 for (i = 0;i < cur->nodeNr;i++)
3545 if (cur->nodeTab[i] == val) return;
3546
3547 /*
3548 * grow the nodeTab if needed
3549 */
3550 if (cur->nodeMax == 0) {
3551 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3552 sizeof(xmlNodePtr));
3553 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003554 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003555 return;
3556 }
3557 memset(cur->nodeTab, 0 ,
3558 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3559 cur->nodeMax = XML_NODESET_DEFAULT;
3560 } else if (cur->nodeNr == cur->nodeMax) {
3561 xmlNodePtr *temp;
3562
3563 cur->nodeMax *= 2;
3564 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3565 sizeof(xmlNodePtr));
3566 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003567 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003568 return;
3569 }
3570 cur->nodeTab = temp;
3571 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003572 if (val->type == XML_NAMESPACE_DECL) {
3573 xmlNsPtr ns = (xmlNsPtr) val;
3574
3575 cur->nodeTab[cur->nodeNr++] =
3576 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3577 } else
3578 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003579}
3580
3581/**
3582 * xmlXPathNodeSetAddUnique:
3583 * @cur: the initial node set
3584 * @val: a new xmlNodePtr
3585 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003586 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00003587 * when we are sure the node is not already in the set.
3588 */
3589void
3590xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00003591 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003592
Daniel Veillardef0b4502003-03-24 13:57:34 +00003593#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00003594 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3595 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00003596#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00003597
William M. Brack08171912003-12-29 02:52:11 +00003598 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003599 /*
3600 * grow the nodeTab if needed
3601 */
3602 if (cur->nodeMax == 0) {
3603 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3604 sizeof(xmlNodePtr));
3605 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003606 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003607 return;
3608 }
3609 memset(cur->nodeTab, 0 ,
3610 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3611 cur->nodeMax = XML_NODESET_DEFAULT;
3612 } else if (cur->nodeNr == cur->nodeMax) {
3613 xmlNodePtr *temp;
3614
3615 cur->nodeMax *= 2;
3616 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3617 sizeof(xmlNodePtr));
3618 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003619 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003620 return;
3621 }
3622 cur->nodeTab = temp;
3623 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003624 if (val->type == XML_NAMESPACE_DECL) {
3625 xmlNsPtr ns = (xmlNsPtr) val;
3626
3627 cur->nodeTab[cur->nodeNr++] =
3628 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3629 } else
3630 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003631}
3632
3633/**
3634 * xmlXPathNodeSetMerge:
3635 * @val1: the first NodeSet or NULL
3636 * @val2: the second NodeSet
3637 *
3638 * Merges two nodesets, all nodes from @val2 are added to @val1
3639 * if @val1 is NULL, a new set is created and copied from @val2
3640 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003641 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003642 */
3643xmlNodeSetPtr
3644xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003645 int i, j, initNr, skip;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003646 xmlNodePtr n1, n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003647
3648 if (val2 == NULL) return(val1);
3649 if (val1 == NULL) {
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003650 val1 = xmlXPathNodeSetCreate(NULL);
3651#if 0
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003652 /*
3653 * TODO: The optimization won't work in every case, since
3654 * those nasty namespace nodes need to be added with
3655 * xmlXPathNodeSetDupNs() to the set; thus a pure
3656 * memcpy is not possible.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00003657 * If there was a flag on the nodesetval, indicating that
3658 * some temporary nodes are in, that would be helpfull.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003659 */
3660 /*
3661 * Optimization: Create an equally sized node-set
3662 * and memcpy the content.
3663 */
3664 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3665 if (val1 == NULL)
3666 return(NULL);
3667 if (val2->nodeNr != 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003668 if (val2->nodeNr == 1)
3669 *(val1->nodeTab) = *(val2->nodeTab);
3670 else {
3671 memcpy(val1->nodeTab, val2->nodeTab,
3672 val2->nodeNr * sizeof(xmlNodePtr));
3673 }
3674 val1->nodeNr = val2->nodeNr;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003675 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003676 return(val1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003677#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003678 }
3679
William M. Brack08171912003-12-29 02:52:11 +00003680 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003681 initNr = val1->nodeNr;
3682
3683 for (i = 0;i < val2->nodeNr;i++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003684 n2 = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00003685 /*
William M. Brack08171912003-12-29 02:52:11 +00003686 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003687 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003688 skip = 0;
3689 for (j = 0; j < initNr; j++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003690 n1 = val1->nodeTab[j];
3691 if (n1 == n2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003692 skip = 1;
3693 break;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003694 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3695 (n2->type == XML_NAMESPACE_DECL)) {
3696 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3697 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3698 ((xmlNsPtr) n2)->prefix)))
3699 {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003700 skip = 1;
3701 break;
3702 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003703 }
3704 }
3705 if (skip)
3706 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00003707
3708 /*
3709 * grow the nodeTab if needed
3710 */
3711 if (val1->nodeMax == 0) {
3712 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3713 sizeof(xmlNodePtr));
3714 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003715 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003716 return(NULL);
3717 }
3718 memset(val1->nodeTab, 0 ,
3719 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3720 val1->nodeMax = XML_NODESET_DEFAULT;
3721 } else if (val1->nodeNr == val1->nodeMax) {
3722 xmlNodePtr *temp;
3723
3724 val1->nodeMax *= 2;
3725 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3726 sizeof(xmlNodePtr));
3727 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003728 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003729 return(NULL);
3730 }
3731 val1->nodeTab = temp;
3732 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003733 if (n2->type == XML_NAMESPACE_DECL) {
3734 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003735
3736 val1->nodeTab[val1->nodeNr++] =
3737 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3738 } else
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003739 val1->nodeTab[val1->nodeNr++] = n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003740 }
3741
3742 return(val1);
3743}
3744
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003745#if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
Owen Taylor3473f882001-02-23 17:55:21 +00003746/**
Daniel Veillard75be0132002-03-13 10:03:35 +00003747 * xmlXPathNodeSetMergeUnique:
3748 * @val1: the first NodeSet or NULL
3749 * @val2: the second NodeSet
3750 *
3751 * Merges two nodesets, all nodes from @val2 are added to @val1
3752 * if @val1 is NULL, a new set is created and copied from @val2
3753 *
3754 * Returns @val1 once extended or NULL in case of error.
3755 */
3756static xmlNodeSetPtr
3757xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00003758 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00003759
3760 if (val2 == NULL) return(val1);
3761 if (val1 == NULL) {
3762 val1 = xmlXPathNodeSetCreate(NULL);
3763 }
3764
William M. Brack08171912003-12-29 02:52:11 +00003765 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00003766
3767 for (i = 0;i < val2->nodeNr;i++) {
3768 /*
3769 * grow the nodeTab if needed
3770 */
3771 if (val1->nodeMax == 0) {
3772 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3773 sizeof(xmlNodePtr));
3774 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003775 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00003776 return(NULL);
3777 }
3778 memset(val1->nodeTab, 0 ,
3779 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3780 val1->nodeMax = XML_NODESET_DEFAULT;
3781 } else if (val1->nodeNr == val1->nodeMax) {
3782 xmlNodePtr *temp;
3783
3784 val1->nodeMax *= 2;
3785 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3786 sizeof(xmlNodePtr));
3787 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003788 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00003789 return(NULL);
3790 }
3791 val1->nodeTab = temp;
3792 }
3793 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3794 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
3795
3796 val1->nodeTab[val1->nodeNr++] =
3797 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3798 } else
3799 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
3800 }
3801
3802 return(val1);
3803}
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003804#endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3805
3806/**
3807 * xmlXPathNodeSetMergeAndClear:
3808 * @set1: the first NodeSet or NULL
3809 * @set2: the second NodeSet
3810 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3811 *
3812 * Merges two nodesets, all nodes from @set2 are added to @set1
3813 * if @set1 is NULL, a new set is created and copied from @set2.
3814 * Checks for duplicate nodes. Clears set2.
3815 *
3816 * Returns @set1 once extended or NULL in case of error.
3817 */
3818static xmlNodeSetPtr
3819xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3820 int hasNullEntries)
3821{
3822 if ((set1 == NULL) && (hasNullEntries == 0)) {
3823 /*
3824 * Note that doing a memcpy of the list, namespace nodes are
3825 * just assigned to set1, since set2 is cleared anyway.
3826 */
3827 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3828 if (set1 == NULL)
3829 return(NULL);
3830 if (set2->nodeNr != 0) {
3831 memcpy(set1->nodeTab, set2->nodeTab,
3832 set2->nodeNr * sizeof(xmlNodePtr));
3833 set1->nodeNr = set2->nodeNr;
3834 }
3835 } else {
3836 int i, j, initNbSet1;
3837 xmlNodePtr n1, n2;
3838
3839 if (set1 == NULL)
3840 set1 = xmlXPathNodeSetCreate(NULL);
3841
3842 initNbSet1 = set1->nodeNr;
3843 for (i = 0;i < set2->nodeNr;i++) {
3844 n2 = set2->nodeTab[i];
3845 /*
3846 * Skip NULLed entries.
3847 */
3848 if (n2 == NULL)
3849 continue;
3850 /*
3851 * Skip duplicates.
3852 */
3853 for (j = 0; j < initNbSet1; j++) {
3854 n1 = set1->nodeTab[j];
3855 if (n1 == n2) {
3856 goto skip_node;
3857 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3858 (n2->type == XML_NAMESPACE_DECL))
3859 {
3860 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3861 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3862 ((xmlNsPtr) n2)->prefix)))
3863 {
3864 /*
3865 * Free the namespace node.
3866 */
3867 set2->nodeTab[i] = NULL;
3868 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3869 goto skip_node;
3870 }
3871 }
3872 }
3873 /*
3874 * grow the nodeTab if needed
3875 */
3876 if (set1->nodeMax == 0) {
3877 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3878 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3879 if (set1->nodeTab == NULL) {
3880 xmlXPathErrMemory(NULL, "merging nodeset\n");
3881 return(NULL);
3882 }
3883 memset(set1->nodeTab, 0,
3884 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3885 set1->nodeMax = XML_NODESET_DEFAULT;
3886 } else if (set1->nodeNr >= set1->nodeMax) {
3887 xmlNodePtr *temp;
3888
3889 set1->nodeMax *= 2;
3890 temp = (xmlNodePtr *) xmlRealloc(
3891 set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3892 if (temp == NULL) {
3893 xmlXPathErrMemory(NULL, "merging nodeset\n");
3894 return(NULL);
3895 }
3896 set1->nodeTab = temp;
3897 }
3898 if (n2->type == XML_NAMESPACE_DECL) {
3899 xmlNsPtr ns = (xmlNsPtr) n2;
3900
3901 set1->nodeTab[set1->nodeNr++] =
3902 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3903 } else
3904 set1->nodeTab[set1->nodeNr++] = n2;
3905skip_node:
3906 {}
3907 }
3908 }
3909 set2->nodeNr = 0;
3910 return(set1);
3911}
3912
3913/**
3914 * xmlXPathNodeSetMergeAndClearNoDupls:
3915 * @set1: the first NodeSet or NULL
3916 * @set2: the second NodeSet
3917 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3918 *
3919 * Merges two nodesets, all nodes from @set2 are added to @set1
3920 * if @set1 is NULL, a new set is created and copied from @set2.
3921 * Doesn't chack for duplicate nodes. Clears set2.
3922 *
3923 * Returns @set1 once extended or NULL in case of error.
3924 */
3925static xmlNodeSetPtr
3926xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3927 int hasNullEntries)
3928{
3929 if (set2 == NULL)
3930 return(set1);
3931 if ((set1 == NULL) && (hasNullEntries == 0)) {
3932 /*
3933 * Note that doing a memcpy of the list, namespace nodes are
3934 * just assigned to set1, since set2 is cleared anyway.
3935 */
3936 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3937 if (set1 == NULL)
3938 return(NULL);
3939 if (set2->nodeNr != 0) {
3940 memcpy(set1->nodeTab, set2->nodeTab,
3941 set2->nodeNr * sizeof(xmlNodePtr));
3942 set1->nodeNr = set2->nodeNr;
3943 }
3944 } else {
3945 int i;
3946 xmlNodePtr n2;
3947
3948 if (set1 == NULL)
3949 set1 = xmlXPathNodeSetCreate(NULL);
3950
3951 for (i = 0;i < set2->nodeNr;i++) {
3952 n2 = set2->nodeTab[i];
3953 /*
3954 * Skip NULLed entries.
3955 */
3956 if (n2 == NULL)
3957 continue;
3958 if (set1->nodeMax == 0) {
3959 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3960 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3961 if (set1->nodeTab == NULL) {
3962 xmlXPathErrMemory(NULL, "merging nodeset\n");
3963 return(NULL);
3964 }
3965 memset(set1->nodeTab, 0,
3966 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3967 set1->nodeMax = XML_NODESET_DEFAULT;
3968 } else if (set1->nodeNr >= set1->nodeMax) {
3969 xmlNodePtr *temp;
3970
3971 set1->nodeMax *= 2;
3972 temp = (xmlNodePtr *) xmlRealloc(
3973 set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3974 if (temp == NULL) {
3975 xmlXPathErrMemory(NULL, "merging nodeset\n");
3976 return(NULL);
3977 }
3978 set1->nodeTab = temp;
3979 }
3980 set1->nodeTab[set1->nodeNr++] = n2;
3981 }
3982 }
3983 set2->nodeNr = 0;
3984 return(set1);
3985}
Daniel Veillard75be0132002-03-13 10:03:35 +00003986
3987/**
Owen Taylor3473f882001-02-23 17:55:21 +00003988 * xmlXPathNodeSetDel:
3989 * @cur: the initial node set
3990 * @val: an xmlNodePtr
3991 *
3992 * Removes an xmlNodePtr from an existing NodeSet
3993 */
3994void
3995xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
3996 int i;
3997
3998 if (cur == NULL) return;
3999 if (val == NULL) return;
4000
4001 /*
William M. Brack08171912003-12-29 02:52:11 +00004002 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00004003 */
4004 for (i = 0;i < cur->nodeNr;i++)
4005 if (cur->nodeTab[i] == val) break;
4006
William M. Brack08171912003-12-29 02:52:11 +00004007 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00004008#ifdef DEBUG
4009 xmlGenericError(xmlGenericErrorContext,
4010 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4011 val->name);
4012#endif
4013 return;
4014 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004015 if ((cur->nodeTab[i] != NULL) &&
4016 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4017 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004018 cur->nodeNr--;
4019 for (;i < cur->nodeNr;i++)
4020 cur->nodeTab[i] = cur->nodeTab[i + 1];
4021 cur->nodeTab[cur->nodeNr] = NULL;
4022}
4023
4024/**
4025 * xmlXPathNodeSetRemove:
4026 * @cur: the initial node set
4027 * @val: the index to remove
4028 *
4029 * Removes an entry from an existing NodeSet list.
4030 */
4031void
4032xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4033 if (cur == NULL) return;
4034 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004035 if ((cur->nodeTab[val] != NULL) &&
4036 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4037 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00004038 cur->nodeNr--;
4039 for (;val < cur->nodeNr;val++)
4040 cur->nodeTab[val] = cur->nodeTab[val + 1];
4041 cur->nodeTab[cur->nodeNr] = NULL;
4042}
4043
4044/**
4045 * xmlXPathFreeNodeSet:
4046 * @obj: the xmlNodeSetPtr to free
4047 *
4048 * Free the NodeSet compound (not the actual nodes !).
4049 */
4050void
4051xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4052 if (obj == NULL) return;
4053 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004054 int i;
4055
William M. Brack08171912003-12-29 02:52:11 +00004056 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004057 for (i = 0;i < obj->nodeNr;i++)
4058 if ((obj->nodeTab[i] != NULL) &&
4059 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4060 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004061 xmlFree(obj->nodeTab);
4062 }
Owen Taylor3473f882001-02-23 17:55:21 +00004063 xmlFree(obj);
4064}
4065
4066/**
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004067 * xmlXPathNodeSetClear:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004068 * @set: the node set to clear
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004069 *
4070 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4071 * are feed), but does *not* free the list itself. Sets the length of the
4072 * list to 0.
4073 */
4074static void
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004075xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4076{
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004077 if ((set == NULL) || (set->nodeNr <= 0))
4078 return;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004079 else if (hasNsNodes) {
4080 int i;
4081 xmlNodePtr node;
4082
4083 for (i = 0; i < set->nodeNr; i++) {
4084 node = set->nodeTab[i];
4085 if ((node != NULL) &&
4086 (node->type == XML_NAMESPACE_DECL))
4087 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4088 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004089 }
4090 set->nodeNr = 0;
4091}
4092
4093/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004094 * xmlXPathNodeSetClearFromPos:
4095 * @set: the node set to be cleared
4096 * @pos: the start position to clear from
4097 *
4098 * Clears the list from temporary XPath objects (e.g. namespace nodes
4099 * are feed) starting with the entry at @pos, but does *not* free the list
4100 * itself. Sets the length of the list to @pos.
4101 */
4102static void
4103xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4104{
4105 if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4106 return;
4107 else if ((hasNsNodes)) {
4108 int i;
4109 xmlNodePtr node;
4110
4111 for (i = pos; i < set->nodeNr; i++) {
4112 node = set->nodeTab[i];
4113 if ((node != NULL) &&
4114 (node->type == XML_NAMESPACE_DECL))
4115 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4116 }
4117 }
4118 set->nodeNr = pos;
4119}
4120
4121/**
Owen Taylor3473f882001-02-23 17:55:21 +00004122 * xmlXPathFreeValueTree:
4123 * @obj: the xmlNodeSetPtr to free
4124 *
4125 * Free the NodeSet compound and the actual tree, this is different
4126 * from xmlXPathFreeNodeSet()
4127 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004128static void
Owen Taylor3473f882001-02-23 17:55:21 +00004129xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4130 int i;
4131
4132 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00004133
4134 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004135 for (i = 0;i < obj->nodeNr;i++) {
4136 if (obj->nodeTab[i] != NULL) {
4137 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4138 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4139 } else {
4140 xmlFreeNodeList(obj->nodeTab[i]);
4141 }
4142 }
4143 }
Owen Taylor3473f882001-02-23 17:55:21 +00004144 xmlFree(obj->nodeTab);
4145 }
Owen Taylor3473f882001-02-23 17:55:21 +00004146 xmlFree(obj);
4147}
4148
4149#if defined(DEBUG) || defined(DEBUG_STEP)
4150/**
4151 * xmlGenericErrorContextNodeSet:
4152 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00004153 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00004154 *
4155 * Quick display of a NodeSet
4156 */
4157void
4158xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4159 int i;
4160
4161 if (output == NULL) output = xmlGenericErrorContext;
4162 if (obj == NULL) {
4163 fprintf(output, "NodeSet == NULL !\n");
4164 return;
4165 }
4166 if (obj->nodeNr == 0) {
4167 fprintf(output, "NodeSet is empty\n");
4168 return;
4169 }
4170 if (obj->nodeTab == NULL) {
4171 fprintf(output, " nodeTab == NULL !\n");
4172 return;
4173 }
4174 for (i = 0; i < obj->nodeNr; i++) {
4175 if (obj->nodeTab[i] == NULL) {
4176 fprintf(output, " NULL !\n");
4177 return;
4178 }
4179 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4180 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4181 fprintf(output, " /");
4182 else if (obj->nodeTab[i]->name == NULL)
4183 fprintf(output, " noname!");
4184 else fprintf(output, " %s", obj->nodeTab[i]->name);
4185 }
4186 fprintf(output, "\n");
4187}
4188#endif
4189
4190/**
4191 * xmlXPathNewNodeSet:
4192 * @val: the NodePtr value
4193 *
4194 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4195 * it with the single Node @val
4196 *
4197 * Returns the newly created object.
4198 */
4199xmlXPathObjectPtr
4200xmlXPathNewNodeSet(xmlNodePtr val) {
4201 xmlXPathObjectPtr ret;
4202
4203 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4204 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004205 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004206 return(NULL);
4207 }
4208 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4209 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00004210 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004211 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00004212 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004213#ifdef XP_DEBUG_OBJ_USAGE
4214 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4215#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004216 return(ret);
4217}
4218
4219/**
4220 * xmlXPathNewValueTree:
4221 * @val: the NodePtr value
4222 *
4223 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4224 * it with the tree root @val
4225 *
4226 * Returns the newly created object.
4227 */
4228xmlXPathObjectPtr
4229xmlXPathNewValueTree(xmlNodePtr val) {
4230 xmlXPathObjectPtr ret;
4231
4232 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4233 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004234 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004235 return(NULL);
4236 }
4237 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4238 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00004239 ret->boolval = 1;
4240 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00004241 ret->nodesetval = xmlXPathNodeSetCreate(val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004242#ifdef XP_DEBUG_OBJ_USAGE
4243 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4244#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004245 return(ret);
4246}
4247
4248/**
4249 * xmlXPathNewNodeSetList:
4250 * @val: an existing NodeSet
4251 *
4252 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4253 * it with the Nodeset @val
4254 *
4255 * Returns the newly created object.
4256 */
4257xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004258xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4259{
Owen Taylor3473f882001-02-23 17:55:21 +00004260 xmlXPathObjectPtr ret;
4261 int i;
4262
4263 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004264 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00004265 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004266 ret = xmlXPathNewNodeSet(NULL);
4267 else {
4268 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4269 for (i = 1; i < val->nodeNr; ++i)
4270 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
4271 }
Owen Taylor3473f882001-02-23 17:55:21 +00004272
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004273 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004274}
4275
4276/**
4277 * xmlXPathWrapNodeSet:
4278 * @val: the NodePtr value
4279 *
4280 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4281 *
4282 * Returns the newly created object.
4283 */
4284xmlXPathObjectPtr
4285xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4286 xmlXPathObjectPtr ret;
4287
4288 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4289 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004290 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004291 return(NULL);
4292 }
4293 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4294 ret->type = XPATH_NODESET;
4295 ret->nodesetval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004296#ifdef XP_DEBUG_OBJ_USAGE
4297 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4298#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004299 return(ret);
4300}
4301
4302/**
4303 * xmlXPathFreeNodeSetList:
4304 * @obj: an existing NodeSetList object
4305 *
4306 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4307 * the list contrary to xmlXPathFreeObject().
4308 */
4309void
4310xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4311 if (obj == NULL) return;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004312#ifdef XP_DEBUG_OBJ_USAGE
4313 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4314#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004315 xmlFree(obj);
4316}
4317
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004318/**
4319 * xmlXPathDifference:
4320 * @nodes1: a node-set
4321 * @nodes2: a node-set
4322 *
4323 * Implements the EXSLT - Sets difference() function:
4324 * node-set set:difference (node-set, node-set)
4325 *
4326 * Returns the difference between the two node sets, or nodes1 if
4327 * nodes2 is empty
4328 */
4329xmlNodeSetPtr
4330xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4331 xmlNodeSetPtr ret;
4332 int i, l1;
4333 xmlNodePtr cur;
4334
4335 if (xmlXPathNodeSetIsEmpty(nodes2))
4336 return(nodes1);
4337
4338 ret = xmlXPathNodeSetCreate(NULL);
4339 if (xmlXPathNodeSetIsEmpty(nodes1))
4340 return(ret);
4341
4342 l1 = xmlXPathNodeSetGetLength(nodes1);
4343
4344 for (i = 0; i < l1; i++) {
4345 cur = xmlXPathNodeSetItem(nodes1, i);
4346 if (!xmlXPathNodeSetContains(nodes2, cur))
4347 xmlXPathNodeSetAddUnique(ret, cur);
4348 }
4349 return(ret);
4350}
4351
4352/**
4353 * xmlXPathIntersection:
4354 * @nodes1: a node-set
4355 * @nodes2: a node-set
4356 *
4357 * Implements the EXSLT - Sets intersection() function:
4358 * node-set set:intersection (node-set, node-set)
4359 *
4360 * Returns a node set comprising the nodes that are within both the
4361 * node sets passed as arguments
4362 */
4363xmlNodeSetPtr
4364xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4365 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4366 int i, l1;
4367 xmlNodePtr cur;
4368
4369 if (xmlXPathNodeSetIsEmpty(nodes1))
4370 return(ret);
4371 if (xmlXPathNodeSetIsEmpty(nodes2))
4372 return(ret);
4373
4374 l1 = xmlXPathNodeSetGetLength(nodes1);
4375
4376 for (i = 0; i < l1; i++) {
4377 cur = xmlXPathNodeSetItem(nodes1, i);
4378 if (xmlXPathNodeSetContains(nodes2, cur))
4379 xmlXPathNodeSetAddUnique(ret, cur);
4380 }
4381 return(ret);
4382}
4383
4384/**
4385 * xmlXPathDistinctSorted:
4386 * @nodes: a node-set, sorted by document order
4387 *
4388 * Implements the EXSLT - Sets distinct() function:
4389 * node-set set:distinct (node-set)
4390 *
4391 * Returns a subset of the nodes contained in @nodes, or @nodes if
4392 * it is empty
4393 */
4394xmlNodeSetPtr
4395xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4396 xmlNodeSetPtr ret;
4397 xmlHashTablePtr hash;
4398 int i, l;
4399 xmlChar * strval;
4400 xmlNodePtr cur;
4401
4402 if (xmlXPathNodeSetIsEmpty(nodes))
4403 return(nodes);
4404
4405 ret = xmlXPathNodeSetCreate(NULL);
4406 l = xmlXPathNodeSetGetLength(nodes);
4407 hash = xmlHashCreate (l);
4408 for (i = 0; i < l; i++) {
4409 cur = xmlXPathNodeSetItem(nodes, i);
4410 strval = xmlXPathCastNodeToString(cur);
4411 if (xmlHashLookup(hash, strval) == NULL) {
4412 xmlHashAddEntry(hash, strval, strval);
4413 xmlXPathNodeSetAddUnique(ret, cur);
4414 } else {
4415 xmlFree(strval);
4416 }
4417 }
4418 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4419 return(ret);
4420}
4421
4422/**
4423 * xmlXPathDistinct:
4424 * @nodes: a node-set
4425 *
4426 * Implements the EXSLT - Sets distinct() function:
4427 * node-set set:distinct (node-set)
4428 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4429 * is called with the sorted node-set
4430 *
4431 * Returns a subset of the nodes contained in @nodes, or @nodes if
4432 * it is empty
4433 */
4434xmlNodeSetPtr
4435xmlXPathDistinct (xmlNodeSetPtr nodes) {
4436 if (xmlXPathNodeSetIsEmpty(nodes))
4437 return(nodes);
4438
4439 xmlXPathNodeSetSort(nodes);
4440 return(xmlXPathDistinctSorted(nodes));
4441}
4442
4443/**
4444 * xmlXPathHasSameNodes:
4445 * @nodes1: a node-set
4446 * @nodes2: a node-set
4447 *
4448 * Implements the EXSLT - Sets has-same-nodes function:
4449 * boolean set:has-same-node(node-set, node-set)
4450 *
4451 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4452 * otherwise
4453 */
4454int
4455xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4456 int i, l;
4457 xmlNodePtr cur;
4458
4459 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4460 xmlXPathNodeSetIsEmpty(nodes2))
4461 return(0);
4462
4463 l = xmlXPathNodeSetGetLength(nodes1);
4464 for (i = 0; i < l; i++) {
4465 cur = xmlXPathNodeSetItem(nodes1, i);
4466 if (xmlXPathNodeSetContains(nodes2, cur))
4467 return(1);
4468 }
4469 return(0);
4470}
4471
4472/**
4473 * xmlXPathNodeLeadingSorted:
4474 * @nodes: a node-set, sorted by document order
4475 * @node: a node
4476 *
4477 * Implements the EXSLT - Sets leading() function:
4478 * node-set set:leading (node-set, node-set)
4479 *
4480 * Returns the nodes in @nodes that precede @node in document order,
4481 * @nodes if @node is NULL or an empty node-set if @nodes
4482 * doesn't contain @node
4483 */
4484xmlNodeSetPtr
4485xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4486 int i, l;
4487 xmlNodePtr cur;
4488 xmlNodeSetPtr ret;
4489
4490 if (node == NULL)
4491 return(nodes);
4492
4493 ret = xmlXPathNodeSetCreate(NULL);
4494 if (xmlXPathNodeSetIsEmpty(nodes) ||
4495 (!xmlXPathNodeSetContains(nodes, node)))
4496 return(ret);
4497
4498 l = xmlXPathNodeSetGetLength(nodes);
4499 for (i = 0; i < l; i++) {
4500 cur = xmlXPathNodeSetItem(nodes, i);
4501 if (cur == node)
4502 break;
4503 xmlXPathNodeSetAddUnique(ret, cur);
4504 }
4505 return(ret);
4506}
4507
4508/**
4509 * xmlXPathNodeLeading:
4510 * @nodes: a node-set
4511 * @node: a node
4512 *
4513 * Implements the EXSLT - Sets leading() function:
4514 * node-set set:leading (node-set, node-set)
4515 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4516 * is called.
4517 *
4518 * Returns the nodes in @nodes that precede @node in document order,
4519 * @nodes if @node is NULL or an empty node-set if @nodes
4520 * doesn't contain @node
4521 */
4522xmlNodeSetPtr
4523xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4524 xmlXPathNodeSetSort(nodes);
4525 return(xmlXPathNodeLeadingSorted(nodes, node));
4526}
4527
4528/**
4529 * xmlXPathLeadingSorted:
4530 * @nodes1: a node-set, sorted by document order
4531 * @nodes2: a node-set, sorted by document order
4532 *
4533 * Implements the EXSLT - Sets leading() function:
4534 * node-set set:leading (node-set, node-set)
4535 *
4536 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4537 * in document order, @nodes1 if @nodes2 is NULL or empty or
4538 * an empty node-set if @nodes1 doesn't contain @nodes2
4539 */
4540xmlNodeSetPtr
4541xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4542 if (xmlXPathNodeSetIsEmpty(nodes2))
4543 return(nodes1);
4544 return(xmlXPathNodeLeadingSorted(nodes1,
4545 xmlXPathNodeSetItem(nodes2, 1)));
4546}
4547
4548/**
4549 * xmlXPathLeading:
4550 * @nodes1: a node-set
4551 * @nodes2: a node-set
4552 *
4553 * Implements the EXSLT - Sets leading() function:
4554 * node-set set:leading (node-set, node-set)
4555 * @nodes1 and @nodes2 are sorted by document order, then
4556 * #exslSetsLeadingSorted is called.
4557 *
4558 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4559 * in document order, @nodes1 if @nodes2 is NULL or empty or
4560 * an empty node-set if @nodes1 doesn't contain @nodes2
4561 */
4562xmlNodeSetPtr
4563xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4564 if (xmlXPathNodeSetIsEmpty(nodes2))
4565 return(nodes1);
4566 if (xmlXPathNodeSetIsEmpty(nodes1))
4567 return(xmlXPathNodeSetCreate(NULL));
4568 xmlXPathNodeSetSort(nodes1);
4569 xmlXPathNodeSetSort(nodes2);
4570 return(xmlXPathNodeLeadingSorted(nodes1,
4571 xmlXPathNodeSetItem(nodes2, 1)));
4572}
4573
4574/**
4575 * xmlXPathNodeTrailingSorted:
4576 * @nodes: a node-set, sorted by document order
4577 * @node: a node
4578 *
4579 * Implements the EXSLT - Sets trailing() function:
4580 * node-set set:trailing (node-set, node-set)
4581 *
4582 * Returns the nodes in @nodes that follow @node in document order,
4583 * @nodes if @node is NULL or an empty node-set if @nodes
4584 * doesn't contain @node
4585 */
4586xmlNodeSetPtr
4587xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4588 int i, l;
4589 xmlNodePtr cur;
4590 xmlNodeSetPtr ret;
4591
4592 if (node == NULL)
4593 return(nodes);
4594
4595 ret = xmlXPathNodeSetCreate(NULL);
4596 if (xmlXPathNodeSetIsEmpty(nodes) ||
4597 (!xmlXPathNodeSetContains(nodes, node)))
4598 return(ret);
4599
4600 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00004601 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004602 cur = xmlXPathNodeSetItem(nodes, i);
4603 if (cur == node)
4604 break;
4605 xmlXPathNodeSetAddUnique(ret, cur);
4606 }
4607 return(ret);
4608}
4609
4610/**
4611 * xmlXPathNodeTrailing:
4612 * @nodes: a node-set
4613 * @node: a node
4614 *
4615 * Implements the EXSLT - Sets trailing() function:
4616 * node-set set:trailing (node-set, node-set)
4617 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4618 * is called.
4619 *
4620 * Returns the nodes in @nodes that follow @node in document order,
4621 * @nodes if @node is NULL or an empty node-set if @nodes
4622 * doesn't contain @node
4623 */
4624xmlNodeSetPtr
4625xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4626 xmlXPathNodeSetSort(nodes);
4627 return(xmlXPathNodeTrailingSorted(nodes, node));
4628}
4629
4630/**
4631 * xmlXPathTrailingSorted:
4632 * @nodes1: a node-set, sorted by document order
4633 * @nodes2: a node-set, sorted by document order
4634 *
4635 * Implements the EXSLT - Sets trailing() function:
4636 * node-set set:trailing (node-set, node-set)
4637 *
4638 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4639 * in document order, @nodes1 if @nodes2 is NULL or empty or
4640 * an empty node-set if @nodes1 doesn't contain @nodes2
4641 */
4642xmlNodeSetPtr
4643xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4644 if (xmlXPathNodeSetIsEmpty(nodes2))
4645 return(nodes1);
4646 return(xmlXPathNodeTrailingSorted(nodes1,
4647 xmlXPathNodeSetItem(nodes2, 0)));
4648}
4649
4650/**
4651 * xmlXPathTrailing:
4652 * @nodes1: a node-set
4653 * @nodes2: a node-set
4654 *
4655 * Implements the EXSLT - Sets trailing() function:
4656 * node-set set:trailing (node-set, node-set)
4657 * @nodes1 and @nodes2 are sorted by document order, then
4658 * #xmlXPathTrailingSorted is called.
4659 *
4660 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4661 * in document order, @nodes1 if @nodes2 is NULL or empty or
4662 * an empty node-set if @nodes1 doesn't contain @nodes2
4663 */
4664xmlNodeSetPtr
4665xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4666 if (xmlXPathNodeSetIsEmpty(nodes2))
4667 return(nodes1);
4668 if (xmlXPathNodeSetIsEmpty(nodes1))
4669 return(xmlXPathNodeSetCreate(NULL));
4670 xmlXPathNodeSetSort(nodes1);
4671 xmlXPathNodeSetSort(nodes2);
4672 return(xmlXPathNodeTrailingSorted(nodes1,
4673 xmlXPathNodeSetItem(nodes2, 0)));
4674}
4675
Owen Taylor3473f882001-02-23 17:55:21 +00004676/************************************************************************
4677 * *
4678 * Routines to handle extra functions *
4679 * *
4680 ************************************************************************/
4681
4682/**
4683 * xmlXPathRegisterFunc:
4684 * @ctxt: the XPath context
4685 * @name: the function name
4686 * @f: the function implementation or NULL
4687 *
4688 * Register a new function. If @f is NULL it unregisters the function
4689 *
4690 * Returns 0 in case of success, -1 in case of error
4691 */
4692int
4693xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4694 xmlXPathFunction f) {
4695 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4696}
4697
4698/**
4699 * xmlXPathRegisterFuncNS:
4700 * @ctxt: the XPath context
4701 * @name: the function name
4702 * @ns_uri: the function namespace URI
4703 * @f: the function implementation or NULL
4704 *
4705 * Register a new function. If @f is NULL it unregisters the function
4706 *
4707 * Returns 0 in case of success, -1 in case of error
4708 */
4709int
4710xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4711 const xmlChar *ns_uri, xmlXPathFunction f) {
4712 if (ctxt == NULL)
4713 return(-1);
4714 if (name == NULL)
4715 return(-1);
4716
4717 if (ctxt->funcHash == NULL)
4718 ctxt->funcHash = xmlHashCreate(0);
4719 if (ctxt->funcHash == NULL)
4720 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004721 if (f == NULL)
4722 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
William M. Brackad0e67c2004-12-01 14:35:10 +00004723 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
Owen Taylor3473f882001-02-23 17:55:21 +00004724}
4725
4726/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00004727 * xmlXPathRegisterFuncLookup:
4728 * @ctxt: the XPath context
4729 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004730 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00004731 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004732 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00004733 */
4734void
4735xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4736 xmlXPathFuncLookupFunc f,
4737 void *funcCtxt) {
4738 if (ctxt == NULL)
4739 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004740 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004741 ctxt->funcLookupData = funcCtxt;
4742}
4743
4744/**
Owen Taylor3473f882001-02-23 17:55:21 +00004745 * xmlXPathFunctionLookup:
4746 * @ctxt: the XPath context
4747 * @name: the function name
4748 *
4749 * Search in the Function array of the context for the given
4750 * function.
4751 *
4752 * Returns the xmlXPathFunction or NULL if not found
4753 */
4754xmlXPathFunction
4755xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00004756 if (ctxt == NULL)
4757 return (NULL);
4758
4759 if (ctxt->funcLookupFunc != NULL) {
4760 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004761 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004762
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004763 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004764 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004765 if (ret != NULL)
4766 return(ret);
4767 }
Owen Taylor3473f882001-02-23 17:55:21 +00004768 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4769}
4770
4771/**
4772 * xmlXPathFunctionLookupNS:
4773 * @ctxt: the XPath context
4774 * @name: the function name
4775 * @ns_uri: the function namespace URI
4776 *
4777 * Search in the Function array of the context for the given
4778 * function.
4779 *
4780 * Returns the xmlXPathFunction or NULL if not found
4781 */
4782xmlXPathFunction
4783xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4784 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00004785 xmlXPathFunction ret;
4786
Owen Taylor3473f882001-02-23 17:55:21 +00004787 if (ctxt == NULL)
4788 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004789 if (name == NULL)
4790 return(NULL);
4791
Thomas Broyerba4ad322001-07-26 16:55:21 +00004792 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004793 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004794
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004795 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004796 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004797 if (ret != NULL)
4798 return(ret);
4799 }
4800
4801 if (ctxt->funcHash == NULL)
4802 return(NULL);
4803
William M. Brackad0e67c2004-12-01 14:35:10 +00004804 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4805 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004806}
4807
4808/**
4809 * xmlXPathRegisteredFuncsCleanup:
4810 * @ctxt: the XPath context
4811 *
4812 * Cleanup the XPath context data associated to registered functions
4813 */
4814void
4815xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4816 if (ctxt == NULL)
4817 return;
4818
4819 xmlHashFree(ctxt->funcHash, NULL);
4820 ctxt->funcHash = NULL;
4821}
4822
4823/************************************************************************
4824 * *
William M. Brack08171912003-12-29 02:52:11 +00004825 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00004826 * *
4827 ************************************************************************/
4828
4829/**
4830 * xmlXPathRegisterVariable:
4831 * @ctxt: the XPath context
4832 * @name: the variable name
4833 * @value: the variable value or NULL
4834 *
4835 * Register a new variable value. If @value is NULL it unregisters
4836 * the variable
4837 *
4838 * Returns 0 in case of success, -1 in case of error
4839 */
4840int
4841xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4842 xmlXPathObjectPtr value) {
4843 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4844}
4845
4846/**
4847 * xmlXPathRegisterVariableNS:
4848 * @ctxt: the XPath context
4849 * @name: the variable name
4850 * @ns_uri: the variable namespace URI
4851 * @value: the variable value or NULL
4852 *
4853 * Register a new variable value. If @value is NULL it unregisters
4854 * the variable
4855 *
4856 * Returns 0 in case of success, -1 in case of error
4857 */
4858int
4859xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4860 const xmlChar *ns_uri,
4861 xmlXPathObjectPtr value) {
4862 if (ctxt == NULL)
4863 return(-1);
4864 if (name == NULL)
4865 return(-1);
4866
4867 if (ctxt->varHash == NULL)
4868 ctxt->varHash = xmlHashCreate(0);
4869 if (ctxt->varHash == NULL)
4870 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004871 if (value == NULL)
4872 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4873 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00004874 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4875 (void *) value,
4876 (xmlHashDeallocator)xmlXPathFreeObject));
4877}
4878
4879/**
4880 * xmlXPathRegisterVariableLookup:
4881 * @ctxt: the XPath context
4882 * @f: the lookup function
4883 * @data: the lookup data
4884 *
4885 * register an external mechanism to do variable lookup
4886 */
4887void
4888xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4889 xmlXPathVariableLookupFunc f, void *data) {
4890 if (ctxt == NULL)
4891 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004892 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00004893 ctxt->varLookupData = data;
4894}
4895
4896/**
4897 * xmlXPathVariableLookup:
4898 * @ctxt: the XPath context
4899 * @name: the variable name
4900 *
4901 * Search in the Variable array of the context for the given
4902 * variable value.
4903 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00004904 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00004905 */
4906xmlXPathObjectPtr
4907xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4908 if (ctxt == NULL)
4909 return(NULL);
4910
4911 if (ctxt->varLookupFunc != NULL) {
4912 xmlXPathObjectPtr ret;
4913
4914 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4915 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00004916 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004917 }
4918 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4919}
4920
4921/**
4922 * xmlXPathVariableLookupNS:
4923 * @ctxt: the XPath context
4924 * @name: the variable name
4925 * @ns_uri: the variable namespace URI
4926 *
4927 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00004928 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00004929 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00004930 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00004931 */
4932xmlXPathObjectPtr
4933xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4934 const xmlChar *ns_uri) {
4935 if (ctxt == NULL)
4936 return(NULL);
4937
4938 if (ctxt->varLookupFunc != NULL) {
4939 xmlXPathObjectPtr ret;
4940
4941 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4942 (ctxt->varLookupData, name, ns_uri);
4943 if (ret != NULL) return(ret);
4944 }
4945
4946 if (ctxt->varHash == NULL)
4947 return(NULL);
4948 if (name == NULL)
4949 return(NULL);
4950
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004951 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
Daniel Veillard8c357d52001-07-03 23:43:33 +00004952 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00004953}
4954
4955/**
4956 * xmlXPathRegisteredVariablesCleanup:
4957 * @ctxt: the XPath context
4958 *
4959 * Cleanup the XPath context data associated to registered variables
4960 */
4961void
4962xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4963 if (ctxt == NULL)
4964 return;
4965
Daniel Veillard76d66f42001-05-16 21:05:17 +00004966 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00004967 ctxt->varHash = NULL;
4968}
4969
4970/**
4971 * xmlXPathRegisterNs:
4972 * @ctxt: the XPath context
4973 * @prefix: the namespace prefix
4974 * @ns_uri: the namespace name
4975 *
4976 * Register a new namespace. If @ns_uri is NULL it unregisters
4977 * the namespace
4978 *
4979 * Returns 0 in case of success, -1 in case of error
4980 */
4981int
4982xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
4983 const xmlChar *ns_uri) {
4984 if (ctxt == NULL)
4985 return(-1);
4986 if (prefix == NULL)
4987 return(-1);
4988
4989 if (ctxt->nsHash == NULL)
4990 ctxt->nsHash = xmlHashCreate(10);
4991 if (ctxt->nsHash == NULL)
4992 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00004993 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00004994 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00004995 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00004996 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00004997 (xmlHashDeallocator)xmlFree));
4998}
4999
5000/**
5001 * xmlXPathNsLookup:
5002 * @ctxt: the XPath context
5003 * @prefix: the namespace prefix value
5004 *
5005 * Search in the namespace declaration array of the context for the given
5006 * namespace name associated to the given prefix
5007 *
5008 * Returns the value or NULL if not found
5009 */
5010const xmlChar *
5011xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5012 if (ctxt == NULL)
5013 return(NULL);
5014 if (prefix == NULL)
5015 return(NULL);
5016
5017#ifdef XML_XML_NAMESPACE
5018 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5019 return(XML_XML_NAMESPACE);
5020#endif
5021
Daniel Veillardc8f620b2001-04-30 20:31:33 +00005022 if (ctxt->namespaces != NULL) {
5023 int i;
5024
5025 for (i = 0;i < ctxt->nsNr;i++) {
5026 if ((ctxt->namespaces[i] != NULL) &&
5027 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5028 return(ctxt->namespaces[i]->href);
5029 }
5030 }
Owen Taylor3473f882001-02-23 17:55:21 +00005031
5032 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5033}
5034
5035/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005036 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00005037 * @ctxt: the XPath context
5038 *
5039 * Cleanup the XPath context data associated to registered variables
5040 */
5041void
5042xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5043 if (ctxt == NULL)
5044 return;
5045
Daniel Veillard42766c02002-08-22 20:52:17 +00005046 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00005047 ctxt->nsHash = NULL;
5048}
5049
5050/************************************************************************
5051 * *
5052 * Routines to handle Values *
5053 * *
5054 ************************************************************************/
5055
William M. Brack08171912003-12-29 02:52:11 +00005056/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005057
5058/**
5059 * xmlXPathNewFloat:
5060 * @val: the double value
5061 *
5062 * Create a new xmlXPathObjectPtr of type double and of value @val
5063 *
5064 * Returns the newly created object.
5065 */
5066xmlXPathObjectPtr
5067xmlXPathNewFloat(double val) {
5068 xmlXPathObjectPtr ret;
5069
5070 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5071 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005072 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005073 return(NULL);
5074 }
5075 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5076 ret->type = XPATH_NUMBER;
5077 ret->floatval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005078#ifdef XP_DEBUG_OBJ_USAGE
5079 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5080#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005081 return(ret);
5082}
5083
5084/**
5085 * xmlXPathNewBoolean:
5086 * @val: the boolean value
5087 *
5088 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5089 *
5090 * Returns the newly created object.
5091 */
5092xmlXPathObjectPtr
5093xmlXPathNewBoolean(int val) {
5094 xmlXPathObjectPtr ret;
5095
5096 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5097 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005098 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005099 return(NULL);
5100 }
5101 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5102 ret->type = XPATH_BOOLEAN;
5103 ret->boolval = (val != 0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005104#ifdef XP_DEBUG_OBJ_USAGE
5105 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5106#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005107 return(ret);
5108}
5109
5110/**
5111 * xmlXPathNewString:
5112 * @val: the xmlChar * value
5113 *
5114 * Create a new xmlXPathObjectPtr of type string and of value @val
5115 *
5116 * Returns the newly created object.
5117 */
5118xmlXPathObjectPtr
5119xmlXPathNewString(const xmlChar *val) {
5120 xmlXPathObjectPtr ret;
5121
5122 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5123 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005124 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005125 return(NULL);
5126 }
5127 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5128 ret->type = XPATH_STRING;
5129 if (val != NULL)
5130 ret->stringval = xmlStrdup(val);
5131 else
5132 ret->stringval = xmlStrdup((const xmlChar *)"");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005133#ifdef XP_DEBUG_OBJ_USAGE
5134 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5135#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005136 return(ret);
5137}
5138
5139/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005140 * xmlXPathWrapString:
5141 * @val: the xmlChar * value
5142 *
5143 * Wraps the @val string into an XPath object.
5144 *
5145 * Returns the newly created object.
5146 */
5147xmlXPathObjectPtr
5148xmlXPathWrapString (xmlChar *val) {
5149 xmlXPathObjectPtr ret;
5150
5151 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5152 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005153 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005154 return(NULL);
5155 }
5156 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5157 ret->type = XPATH_STRING;
5158 ret->stringval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005159#ifdef XP_DEBUG_OBJ_USAGE
5160 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5161#endif
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005162 return(ret);
5163}
5164
5165/**
Owen Taylor3473f882001-02-23 17:55:21 +00005166 * xmlXPathNewCString:
5167 * @val: the char * value
5168 *
5169 * Create a new xmlXPathObjectPtr of type string and of value @val
5170 *
5171 * Returns the newly created object.
5172 */
5173xmlXPathObjectPtr
5174xmlXPathNewCString(const char *val) {
5175 xmlXPathObjectPtr ret;
5176
5177 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5178 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005179 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005180 return(NULL);
5181 }
5182 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5183 ret->type = XPATH_STRING;
5184 ret->stringval = xmlStrdup(BAD_CAST val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005185#ifdef XP_DEBUG_OBJ_USAGE
5186 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5187#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005188 return(ret);
5189}
5190
5191/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005192 * xmlXPathWrapCString:
5193 * @val: the char * value
5194 *
5195 * Wraps a string into an XPath object.
5196 *
5197 * Returns the newly created object.
5198 */
5199xmlXPathObjectPtr
5200xmlXPathWrapCString (char * val) {
5201 return(xmlXPathWrapString((xmlChar *)(val)));
5202}
5203
5204/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005205 * xmlXPathWrapExternal:
5206 * @val: the user data
5207 *
5208 * Wraps the @val data into an XPath object.
5209 *
5210 * Returns the newly created object.
5211 */
5212xmlXPathObjectPtr
5213xmlXPathWrapExternal (void *val) {
5214 xmlXPathObjectPtr ret;
5215
5216 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5217 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005218 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005219 return(NULL);
5220 }
5221 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5222 ret->type = XPATH_USERS;
5223 ret->user = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005224#ifdef XP_DEBUG_OBJ_USAGE
5225 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5226#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005227 return(ret);
5228}
5229
5230/**
Owen Taylor3473f882001-02-23 17:55:21 +00005231 * xmlXPathObjectCopy:
5232 * @val: the original object
5233 *
5234 * allocate a new copy of a given object
5235 *
5236 * Returns the newly created object.
5237 */
5238xmlXPathObjectPtr
5239xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5240 xmlXPathObjectPtr ret;
5241
5242 if (val == NULL)
5243 return(NULL);
5244
5245 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5246 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005247 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005248 return(NULL);
5249 }
5250 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005251#ifdef XP_DEBUG_OBJ_USAGE
5252 xmlXPathDebugObjUsageRequested(NULL, val->type);
5253#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005254 switch (val->type) {
5255 case XPATH_BOOLEAN:
5256 case XPATH_NUMBER:
5257 case XPATH_POINT:
5258 case XPATH_RANGE:
5259 break;
5260 case XPATH_STRING:
5261 ret->stringval = xmlStrdup(val->stringval);
5262 break;
5263 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00005264#if 0
5265/*
5266 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5267 this previous handling is no longer correct, and can cause some serious
5268 problems (ref. bug 145547)
5269*/
Owen Taylor3473f882001-02-23 17:55:21 +00005270 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005271 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005272 xmlNodePtr cur, tmp;
5273 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005274
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005275 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005276 top = xmlNewDoc(NULL);
5277 top->name = (char *)
5278 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005279 ret->user = top;
5280 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005281 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005282 cur = val->nodesetval->nodeTab[0]->children;
5283 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005284 tmp = xmlDocCopyNode(cur, top, 1);
5285 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005286 cur = cur->next;
5287 }
5288 }
William M. Bracke9449c52004-07-11 14:41:20 +00005289
Daniel Veillard9adc0462003-03-24 18:39:54 +00005290 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005291 } else
Owen Taylor3473f882001-02-23 17:55:21 +00005292 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005293 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00005294 break;
William M. Bracke9449c52004-07-11 14:41:20 +00005295#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005296 case XPATH_NODESET:
5297 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005298 /* Do not deallocate the copied tree value */
5299 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005300 break;
5301 case XPATH_LOCATIONSET:
5302#ifdef LIBXML_XPTR_ENABLED
5303 {
5304 xmlLocationSetPtr loc = val->user;
5305 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5306 break;
5307 }
5308#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00005309 case XPATH_USERS:
5310 ret->user = val->user;
5311 break;
5312 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00005313 xmlGenericError(xmlGenericErrorContext,
5314 "xmlXPathObjectCopy: unsupported type %d\n",
5315 val->type);
5316 break;
5317 }
5318 return(ret);
5319}
5320
5321/**
5322 * xmlXPathFreeObject:
5323 * @obj: the object to free
5324 *
5325 * Free up an xmlXPathObjectPtr object.
5326 */
5327void
5328xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5329 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005330 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00005331 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00005332#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005333 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005334 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00005335 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00005336 } else
5337#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005338 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
William M. Bracke9449c52004-07-11 14:41:20 +00005339 if (obj->nodesetval != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005340 xmlXPathFreeValueTree(obj->nodesetval);
Daniel Veillard77851712001-02-27 21:54:07 +00005341 } else {
5342 if (obj->nodesetval != NULL)
5343 xmlXPathFreeNodeSet(obj->nodesetval);
5344 }
Owen Taylor3473f882001-02-23 17:55:21 +00005345#ifdef LIBXML_XPTR_ENABLED
5346 } else if (obj->type == XPATH_LOCATIONSET) {
5347 if (obj->user != NULL)
5348 xmlXPtrFreeLocationSet(obj->user);
5349#endif
5350 } else if (obj->type == XPATH_STRING) {
5351 if (obj->stringval != NULL)
5352 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005353 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005354#ifdef XP_DEBUG_OBJ_USAGE
5355 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5356#endif
5357 xmlFree(obj);
5358}
Owen Taylor3473f882001-02-23 17:55:21 +00005359
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005360/**
5361 * xmlXPathReleaseObject:
5362 * @obj: the xmlXPathObjectPtr to free or to cache
5363 *
5364 * Depending on the state of the cache this frees the given
5365 * XPath object or stores it in the cache.
5366 */
5367static void
5368xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5369{
5370#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5371 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5372 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5373
5374#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5375
5376 if (obj == NULL)
5377 return;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005378 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005379 xmlXPathFreeObject(obj);
5380 } else {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005381 xmlXPathContextCachePtr cache =
5382 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005383
5384 switch (obj->type) {
5385 case XPATH_NODESET:
5386 case XPATH_XSLT_TREE:
5387 if (obj->nodesetval != NULL) {
5388 if (obj->boolval) {
5389 /*
5390 * It looks like the @boolval is used for
5391 * evaluation if this an XSLT Result Tree Fragment.
5392 * TODO: Check if this assumption is correct.
5393 */
5394 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5395 xmlXPathFreeValueTree(obj->nodesetval);
5396 obj->nodesetval = NULL;
5397 } else if ((obj->nodesetval->nodeMax <= 40) &&
5398 (XP_CACHE_WANTS(cache->nodesetObjs,
5399 cache->maxNodeset)))
5400 {
5401 XP_CACHE_ADD(cache->nodesetObjs, obj);
5402 goto obj_cached;
5403 } else {
5404 xmlXPathFreeNodeSet(obj->nodesetval);
5405 obj->nodesetval = NULL;
5406 }
5407 }
5408 break;
5409 case XPATH_STRING:
5410 if (obj->stringval != NULL)
5411 xmlFree(obj->stringval);
5412
5413 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5414 XP_CACHE_ADD(cache->stringObjs, obj);
5415 goto obj_cached;
5416 }
5417 break;
5418 case XPATH_BOOLEAN:
5419 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5420 XP_CACHE_ADD(cache->booleanObjs, obj);
5421 goto obj_cached;
5422 }
5423 break;
5424 case XPATH_NUMBER:
5425 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5426 XP_CACHE_ADD(cache->numberObjs, obj);
5427 goto obj_cached;
5428 }
5429 break;
5430#ifdef LIBXML_XPTR_ENABLED
5431 case XPATH_LOCATIONSET:
5432 if (obj->user != NULL) {
5433 xmlXPtrFreeLocationSet(obj->user);
5434 }
5435 goto free_obj;
5436#endif
5437 default:
5438 goto free_obj;
5439 }
5440
5441 /*
5442 * Fallback to adding to the misc-objects slot.
5443 */
5444 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5445 XP_CACHE_ADD(cache->miscObjs, obj);
5446 } else
5447 goto free_obj;
5448
5449obj_cached:
5450
5451#ifdef XP_DEBUG_OBJ_USAGE
5452 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5453#endif
5454
5455 if (obj->nodesetval != NULL) {
5456 xmlNodeSetPtr tmpset = obj->nodesetval;
5457
5458 /*
5459 * TODO: Due to those nasty ns-nodes, we need to traverse
5460 * the list and free the ns-nodes.
5461 * URGENT TODO: Check if it's actually slowing things down.
5462 * Maybe we shouldn't try to preserve the list.
5463 */
5464 if (tmpset->nodeNr > 1) {
5465 int i;
5466 xmlNodePtr node;
5467
5468 for (i = 0; i < tmpset->nodeNr; i++) {
5469 node = tmpset->nodeTab[i];
5470 if ((node != NULL) &&
5471 (node->type == XML_NAMESPACE_DECL))
5472 {
5473 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5474 }
5475 }
5476 } else if (tmpset->nodeNr == 1) {
5477 if ((tmpset->nodeTab[0] != NULL) &&
5478 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5479 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5480 }
5481 tmpset->nodeNr = 0;
5482 memset(obj, 0, sizeof(xmlXPathObject));
5483 obj->nodesetval = tmpset;
5484 } else
5485 memset(obj, 0, sizeof(xmlXPathObject));
5486
5487 return;
5488
5489free_obj:
5490 /*
5491 * Cache is full; free the object.
5492 */
5493 if (obj->nodesetval != NULL)
5494 xmlXPathFreeNodeSet(obj->nodesetval);
5495#ifdef XP_DEBUG_OBJ_USAGE
5496 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5497#endif
5498 xmlFree(obj);
5499 }
5500 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005501}
5502
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005503
5504/************************************************************************
5505 * *
5506 * Type Casting Routines *
5507 * *
5508 ************************************************************************/
5509
5510/**
5511 * xmlXPathCastBooleanToString:
5512 * @val: a boolean
5513 *
5514 * Converts a boolean to its string value.
5515 *
5516 * Returns a newly allocated string.
5517 */
5518xmlChar *
5519xmlXPathCastBooleanToString (int val) {
5520 xmlChar *ret;
5521 if (val)
5522 ret = xmlStrdup((const xmlChar *) "true");
5523 else
5524 ret = xmlStrdup((const xmlChar *) "false");
5525 return(ret);
5526}
5527
5528/**
5529 * xmlXPathCastNumberToString:
5530 * @val: a number
5531 *
5532 * Converts a number to its string value.
5533 *
5534 * Returns a newly allocated string.
5535 */
5536xmlChar *
5537xmlXPathCastNumberToString (double val) {
5538 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00005539 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005540 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005541 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005542 break;
5543 case -1:
5544 ret = xmlStrdup((const xmlChar *) "-Infinity");
5545 break;
5546 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00005547 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005548 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005549 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5550 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005551 } else {
5552 /* could be improved */
5553 char buf[100];
Daniel Veillard11ce4002006-03-10 00:36:23 +00005554 xmlXPathFormatNumber(val, buf, 99);
5555 buf[99] = 0;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005556 ret = xmlStrdup((const xmlChar *) buf);
5557 }
5558 }
5559 return(ret);
5560}
5561
5562/**
5563 * xmlXPathCastNodeToString:
5564 * @node: a node
5565 *
5566 * Converts a node to its string value.
5567 *
5568 * Returns a newly allocated string.
5569 */
5570xmlChar *
5571xmlXPathCastNodeToString (xmlNodePtr node) {
5572 return(xmlNodeGetContent(node));
5573}
5574
5575/**
5576 * xmlXPathCastNodeSetToString:
5577 * @ns: a node-set
5578 *
5579 * Converts a node-set to its string value.
5580 *
5581 * Returns a newly allocated string.
5582 */
5583xmlChar *
5584xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5585 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5586 return(xmlStrdup((const xmlChar *) ""));
5587
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00005588 if (ns->nodeNr > 1)
5589 xmlXPathNodeSetSort(ns);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005590 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5591}
5592
5593/**
5594 * xmlXPathCastToString:
5595 * @val: an XPath object
5596 *
5597 * Converts an existing object to its string() equivalent
5598 *
5599 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005600 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005601 * string object).
5602 */
5603xmlChar *
5604xmlXPathCastToString(xmlXPathObjectPtr val) {
5605 xmlChar *ret = NULL;
5606
5607 if (val == NULL)
5608 return(xmlStrdup((const xmlChar *) ""));
5609 switch (val->type) {
5610 case XPATH_UNDEFINED:
5611#ifdef DEBUG_EXPR
5612 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5613#endif
5614 ret = xmlStrdup((const xmlChar *) "");
5615 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005616 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005617 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005618 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5619 break;
5620 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00005621 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005622 case XPATH_BOOLEAN:
5623 ret = xmlXPathCastBooleanToString(val->boolval);
5624 break;
5625 case XPATH_NUMBER: {
5626 ret = xmlXPathCastNumberToString(val->floatval);
5627 break;
5628 }
5629 case XPATH_USERS:
5630 case XPATH_POINT:
5631 case XPATH_RANGE:
5632 case XPATH_LOCATIONSET:
5633 TODO
5634 ret = xmlStrdup((const xmlChar *) "");
5635 break;
5636 }
5637 return(ret);
5638}
5639
5640/**
5641 * xmlXPathConvertString:
5642 * @val: an XPath object
5643 *
5644 * Converts an existing object to its string() equivalent
5645 *
5646 * Returns the new object, the old one is freed (or the operation
5647 * is done directly on @val)
5648 */
5649xmlXPathObjectPtr
5650xmlXPathConvertString(xmlXPathObjectPtr val) {
5651 xmlChar *res = NULL;
5652
5653 if (val == NULL)
5654 return(xmlXPathNewCString(""));
5655
5656 switch (val->type) {
5657 case XPATH_UNDEFINED:
5658#ifdef DEBUG_EXPR
5659 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5660#endif
5661 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005662 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005663 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005664 res = xmlXPathCastNodeSetToString(val->nodesetval);
5665 break;
5666 case XPATH_STRING:
5667 return(val);
5668 case XPATH_BOOLEAN:
5669 res = xmlXPathCastBooleanToString(val->boolval);
5670 break;
5671 case XPATH_NUMBER:
5672 res = xmlXPathCastNumberToString(val->floatval);
5673 break;
5674 case XPATH_USERS:
5675 case XPATH_POINT:
5676 case XPATH_RANGE:
5677 case XPATH_LOCATIONSET:
5678 TODO;
5679 break;
5680 }
5681 xmlXPathFreeObject(val);
5682 if (res == NULL)
5683 return(xmlXPathNewCString(""));
5684 return(xmlXPathWrapString(res));
5685}
5686
5687/**
5688 * xmlXPathCastBooleanToNumber:
5689 * @val: a boolean
5690 *
5691 * Converts a boolean to its number value
5692 *
5693 * Returns the number value
5694 */
5695double
5696xmlXPathCastBooleanToNumber(int val) {
5697 if (val)
5698 return(1.0);
5699 return(0.0);
5700}
5701
5702/**
5703 * xmlXPathCastStringToNumber:
5704 * @val: a string
5705 *
5706 * Converts a string to its number value
5707 *
5708 * Returns the number value
5709 */
5710double
5711xmlXPathCastStringToNumber(const xmlChar * val) {
5712 return(xmlXPathStringEvalNumber(val));
5713}
5714
5715/**
5716 * xmlXPathCastNodeToNumber:
5717 * @node: a node
5718 *
5719 * Converts a node to its number value
5720 *
5721 * Returns the number value
5722 */
5723double
5724xmlXPathCastNodeToNumber (xmlNodePtr node) {
5725 xmlChar *strval;
5726 double ret;
5727
5728 if (node == NULL)
5729 return(xmlXPathNAN);
5730 strval = xmlXPathCastNodeToString(node);
5731 if (strval == NULL)
5732 return(xmlXPathNAN);
5733 ret = xmlXPathCastStringToNumber(strval);
5734 xmlFree(strval);
5735
5736 return(ret);
5737}
5738
5739/**
5740 * xmlXPathCastNodeSetToNumber:
5741 * @ns: a node-set
5742 *
5743 * Converts a node-set to its number value
5744 *
5745 * Returns the number value
5746 */
5747double
5748xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5749 xmlChar *str;
5750 double ret;
5751
5752 if (ns == NULL)
5753 return(xmlXPathNAN);
5754 str = xmlXPathCastNodeSetToString(ns);
5755 ret = xmlXPathCastStringToNumber(str);
5756 xmlFree(str);
5757 return(ret);
5758}
5759
5760/**
5761 * xmlXPathCastToNumber:
5762 * @val: an XPath object
5763 *
5764 * Converts an XPath object to its number value
5765 *
5766 * Returns the number value
5767 */
5768double
5769xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5770 double ret = 0.0;
5771
5772 if (val == NULL)
5773 return(xmlXPathNAN);
5774 switch (val->type) {
5775 case XPATH_UNDEFINED:
5776#ifdef DEGUB_EXPR
5777 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5778#endif
5779 ret = xmlXPathNAN;
5780 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005781 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005782 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005783 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5784 break;
5785 case XPATH_STRING:
5786 ret = xmlXPathCastStringToNumber(val->stringval);
5787 break;
5788 case XPATH_NUMBER:
5789 ret = val->floatval;
5790 break;
5791 case XPATH_BOOLEAN:
5792 ret = xmlXPathCastBooleanToNumber(val->boolval);
5793 break;
5794 case XPATH_USERS:
5795 case XPATH_POINT:
5796 case XPATH_RANGE:
5797 case XPATH_LOCATIONSET:
5798 TODO;
5799 ret = xmlXPathNAN;
5800 break;
5801 }
5802 return(ret);
5803}
5804
5805/**
5806 * xmlXPathConvertNumber:
5807 * @val: an XPath object
5808 *
5809 * Converts an existing object to its number() equivalent
5810 *
5811 * Returns the new object, the old one is freed (or the operation
5812 * is done directly on @val)
5813 */
5814xmlXPathObjectPtr
5815xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5816 xmlXPathObjectPtr ret;
5817
5818 if (val == NULL)
5819 return(xmlXPathNewFloat(0.0));
5820 if (val->type == XPATH_NUMBER)
5821 return(val);
5822 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5823 xmlXPathFreeObject(val);
5824 return(ret);
5825}
5826
5827/**
5828 * xmlXPathCastNumberToBoolean:
5829 * @val: a number
5830 *
5831 * Converts a number to its boolean value
5832 *
5833 * Returns the boolean value
5834 */
5835int
5836xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00005837 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005838 return(0);
5839 return(1);
5840}
5841
5842/**
5843 * xmlXPathCastStringToBoolean:
5844 * @val: a string
5845 *
5846 * Converts a string to its boolean value
5847 *
5848 * Returns the boolean value
5849 */
5850int
5851xmlXPathCastStringToBoolean (const xmlChar *val) {
5852 if ((val == NULL) || (xmlStrlen(val) == 0))
5853 return(0);
5854 return(1);
5855}
5856
5857/**
5858 * xmlXPathCastNodeSetToBoolean:
5859 * @ns: a node-set
5860 *
5861 * Converts a node-set to its boolean value
5862 *
5863 * Returns the boolean value
5864 */
5865int
5866xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5867 if ((ns == NULL) || (ns->nodeNr == 0))
5868 return(0);
5869 return(1);
5870}
5871
5872/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005873 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005874 * @val: an XPath object
5875 *
5876 * Converts an XPath object to its boolean value
5877 *
5878 * Returns the boolean value
5879 */
5880int
5881xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5882 int ret = 0;
5883
5884 if (val == NULL)
5885 return(0);
5886 switch (val->type) {
5887 case XPATH_UNDEFINED:
5888#ifdef DEBUG_EXPR
5889 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
5890#endif
5891 ret = 0;
5892 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005893 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005894 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005895 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5896 break;
5897 case XPATH_STRING:
5898 ret = xmlXPathCastStringToBoolean(val->stringval);
5899 break;
5900 case XPATH_NUMBER:
5901 ret = xmlXPathCastNumberToBoolean(val->floatval);
5902 break;
5903 case XPATH_BOOLEAN:
5904 ret = val->boolval;
5905 break;
5906 case XPATH_USERS:
5907 case XPATH_POINT:
5908 case XPATH_RANGE:
5909 case XPATH_LOCATIONSET:
5910 TODO;
5911 ret = 0;
5912 break;
5913 }
5914 return(ret);
5915}
5916
5917
5918/**
5919 * xmlXPathConvertBoolean:
5920 * @val: an XPath object
5921 *
5922 * Converts an existing object to its boolean() equivalent
5923 *
5924 * Returns the new object, the old one is freed (or the operation
5925 * is done directly on @val)
5926 */
5927xmlXPathObjectPtr
5928xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
5929 xmlXPathObjectPtr ret;
5930
5931 if (val == NULL)
5932 return(xmlXPathNewBoolean(0));
5933 if (val->type == XPATH_BOOLEAN)
5934 return(val);
5935 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
5936 xmlXPathFreeObject(val);
5937 return(ret);
5938}
5939
Owen Taylor3473f882001-02-23 17:55:21 +00005940/************************************************************************
5941 * *
5942 * Routines to handle XPath contexts *
5943 * *
5944 ************************************************************************/
5945
5946/**
5947 * xmlXPathNewContext:
5948 * @doc: the XML document
5949 *
5950 * Create a new xmlXPathContext
5951 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00005952 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00005953 */
5954xmlXPathContextPtr
5955xmlXPathNewContext(xmlDocPtr doc) {
5956 xmlXPathContextPtr ret;
5957
5958 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
5959 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005960 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005961 return(NULL);
5962 }
5963 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
5964 ret->doc = doc;
5965 ret->node = NULL;
5966
5967 ret->varHash = NULL;
5968
5969 ret->nb_types = 0;
5970 ret->max_types = 0;
5971 ret->types = NULL;
5972
5973 ret->funcHash = xmlHashCreate(0);
5974
5975 ret->nb_axis = 0;
5976 ret->max_axis = 0;
5977 ret->axis = NULL;
5978
5979 ret->nsHash = NULL;
5980 ret->user = NULL;
5981
5982 ret->contextSize = -1;
5983 ret->proximityPosition = -1;
5984
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005985#ifdef XP_DEFAULT_CACHE_ON
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005986 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005987 xmlXPathFreeContext(ret);
5988 return(NULL);
5989 }
5990#endif
5991
5992 xmlXPathRegisterAllFunctions(ret);
5993
Owen Taylor3473f882001-02-23 17:55:21 +00005994 return(ret);
5995}
5996
5997/**
5998 * xmlXPathFreeContext:
5999 * @ctxt: the context to free
6000 *
6001 * Free up an xmlXPathContext
6002 */
6003void
6004xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006005 if (ctxt == NULL) return;
6006
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006007 if (ctxt->cache != NULL)
6008 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
Owen Taylor3473f882001-02-23 17:55:21 +00006009 xmlXPathRegisteredNsCleanup(ctxt);
6010 xmlXPathRegisteredFuncsCleanup(ctxt);
6011 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006012 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00006013 xmlFree(ctxt);
6014}
6015
6016/************************************************************************
6017 * *
6018 * Routines to handle XPath parser contexts *
6019 * *
6020 ************************************************************************/
6021
6022#define CHECK_CTXT(ctxt) \
6023 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00006024 __xmlRaiseError(NULL, NULL, NULL, \
6025 NULL, NULL, XML_FROM_XPATH, \
6026 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6027 __FILE__, __LINE__, \
6028 NULL, NULL, NULL, 0, 0, \
6029 "NULL context pointer\n"); \
6030 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00006031 } \
6032
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006033#define CHECK_CTXT_NEG(ctxt) \
6034 if (ctxt == NULL) { \
6035 __xmlRaiseError(NULL, NULL, NULL, \
6036 NULL, NULL, XML_FROM_XPATH, \
6037 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6038 __FILE__, __LINE__, \
6039 NULL, NULL, NULL, 0, 0, \
6040 "NULL context pointer\n"); \
6041 return(-1); \
6042 } \
6043
Owen Taylor3473f882001-02-23 17:55:21 +00006044
6045#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00006046 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
6047 (ctxt->doc->children == NULL)) { \
6048 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00006049 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00006050 }
Owen Taylor3473f882001-02-23 17:55:21 +00006051
6052
6053/**
6054 * xmlXPathNewParserContext:
6055 * @str: the XPath expression
6056 * @ctxt: the XPath context
6057 *
6058 * Create a new xmlXPathParserContext
6059 *
6060 * Returns the xmlXPathParserContext just allocated.
6061 */
6062xmlXPathParserContextPtr
6063xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6064 xmlXPathParserContextPtr ret;
6065
6066 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6067 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006068 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006069 return(NULL);
6070 }
6071 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6072 ret->cur = ret->base = str;
6073 ret->context = ctxt;
6074
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006075 ret->comp = xmlXPathNewCompExpr();
6076 if (ret->comp == NULL) {
6077 xmlFree(ret->valueTab);
6078 xmlFree(ret);
6079 return(NULL);
6080 }
Daniel Veillard4773df22004-01-23 13:15:13 +00006081 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6082 ret->comp->dict = ctxt->dict;
6083 xmlDictReference(ret->comp->dict);
6084 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006085
6086 return(ret);
6087}
6088
6089/**
6090 * xmlXPathCompParserContext:
6091 * @comp: the XPath compiled expression
6092 * @ctxt: the XPath context
6093 *
6094 * Create a new xmlXPathParserContext when processing a compiled expression
6095 *
6096 * Returns the xmlXPathParserContext just allocated.
6097 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006098static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006099xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6100 xmlXPathParserContextPtr ret;
6101
6102 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6103 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006104 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006105 return(NULL);
6106 }
6107 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6108
Owen Taylor3473f882001-02-23 17:55:21 +00006109 /* Allocate the value stack */
6110 ret->valueTab = (xmlXPathObjectPtr *)
6111 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006112 if (ret->valueTab == NULL) {
6113 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006114 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006115 return(NULL);
6116 }
Owen Taylor3473f882001-02-23 17:55:21 +00006117 ret->valueNr = 0;
6118 ret->valueMax = 10;
6119 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006120
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006121 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006122 ret->comp = comp;
6123
Owen Taylor3473f882001-02-23 17:55:21 +00006124 return(ret);
6125}
6126
6127/**
6128 * xmlXPathFreeParserContext:
6129 * @ctxt: the context to free
6130 *
6131 * Free up an xmlXPathParserContext
6132 */
6133void
6134xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6135 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006136 xmlFree(ctxt->valueTab);
6137 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00006138 if (ctxt->comp != NULL) {
6139#ifdef XPATH_STREAMING
6140 if (ctxt->comp->stream != NULL) {
6141 xmlFreePatternList(ctxt->comp->stream);
6142 ctxt->comp->stream = NULL;
6143 }
6144#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006145 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard56de87e2005-02-16 00:22:29 +00006146 }
Owen Taylor3473f882001-02-23 17:55:21 +00006147 xmlFree(ctxt);
6148}
6149
6150/************************************************************************
6151 * *
6152 * The implicit core function library *
6153 * *
6154 ************************************************************************/
6155
Owen Taylor3473f882001-02-23 17:55:21 +00006156/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006157 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00006158 * @node: a node pointer
6159 *
6160 * Function computing the beginning of the string value of the node,
6161 * used to speed up comparisons
6162 *
6163 * Returns an int usable as a hash
6164 */
6165static unsigned int
6166xmlXPathNodeValHash(xmlNodePtr node) {
6167 int len = 2;
6168 const xmlChar * string = NULL;
6169 xmlNodePtr tmp = NULL;
6170 unsigned int ret = 0;
6171
6172 if (node == NULL)
6173 return(0);
6174
Daniel Veillard9adc0462003-03-24 18:39:54 +00006175 if (node->type == XML_DOCUMENT_NODE) {
6176 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6177 if (tmp == NULL)
6178 node = node->children;
6179 else
6180 node = tmp;
6181
6182 if (node == NULL)
6183 return(0);
6184 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006185
6186 switch (node->type) {
6187 case XML_COMMENT_NODE:
6188 case XML_PI_NODE:
6189 case XML_CDATA_SECTION_NODE:
6190 case XML_TEXT_NODE:
6191 string = node->content;
6192 if (string == NULL)
6193 return(0);
6194 if (string[0] == 0)
6195 return(0);
6196 return(((unsigned int) string[0]) +
6197 (((unsigned int) string[1]) << 8));
6198 case XML_NAMESPACE_DECL:
6199 string = ((xmlNsPtr)node)->href;
6200 if (string == NULL)
6201 return(0);
6202 if (string[0] == 0)
6203 return(0);
6204 return(((unsigned int) string[0]) +
6205 (((unsigned int) string[1]) << 8));
6206 case XML_ATTRIBUTE_NODE:
6207 tmp = ((xmlAttrPtr) node)->children;
6208 break;
6209 case XML_ELEMENT_NODE:
6210 tmp = node->children;
6211 break;
6212 default:
6213 return(0);
6214 }
6215 while (tmp != NULL) {
6216 switch (tmp->type) {
6217 case XML_COMMENT_NODE:
6218 case XML_PI_NODE:
6219 case XML_CDATA_SECTION_NODE:
6220 case XML_TEXT_NODE:
6221 string = tmp->content;
6222 break;
6223 case XML_NAMESPACE_DECL:
6224 string = ((xmlNsPtr)tmp)->href;
6225 break;
6226 default:
6227 break;
6228 }
6229 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006230 if (len == 1) {
6231 return(ret + (((unsigned int) string[0]) << 8));
6232 }
6233 if (string[1] == 0) {
6234 len = 1;
6235 ret = (unsigned int) string[0];
6236 } else {
6237 return(((unsigned int) string[0]) +
6238 (((unsigned int) string[1]) << 8));
6239 }
6240 }
6241 /*
6242 * Skip to next node
6243 */
6244 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6245 if (tmp->children->type != XML_ENTITY_DECL) {
6246 tmp = tmp->children;
6247 continue;
6248 }
6249 }
6250 if (tmp == node)
6251 break;
6252
6253 if (tmp->next != NULL) {
6254 tmp = tmp->next;
6255 continue;
6256 }
6257
6258 do {
6259 tmp = tmp->parent;
6260 if (tmp == NULL)
6261 break;
6262 if (tmp == node) {
6263 tmp = NULL;
6264 break;
6265 }
6266 if (tmp->next != NULL) {
6267 tmp = tmp->next;
6268 break;
6269 }
6270 } while (tmp != NULL);
6271 }
6272 return(ret);
6273}
6274
6275/**
6276 * xmlXPathStringHash:
6277 * @string: a string
6278 *
6279 * Function computing the beginning of the string value of the node,
6280 * used to speed up comparisons
6281 *
6282 * Returns an int usable as a hash
6283 */
6284static unsigned int
6285xmlXPathStringHash(const xmlChar * string) {
6286 if (string == NULL)
6287 return((unsigned int) 0);
6288 if (string[0] == 0)
6289 return(0);
6290 return(((unsigned int) string[0]) +
6291 (((unsigned int) string[1]) << 8));
6292}
6293
6294/**
Owen Taylor3473f882001-02-23 17:55:21 +00006295 * xmlXPathCompareNodeSetFloat:
6296 * @ctxt: the XPath Parser context
6297 * @inf: less than (1) or greater than (0)
6298 * @strict: is the comparison strict
6299 * @arg: the node set
6300 * @f: the value
6301 *
6302 * Implement the compare operation between a nodeset and a number
6303 * @ns < @val (1, 1, ...
6304 * @ns <= @val (1, 0, ...
6305 * @ns > @val (0, 1, ...
6306 * @ns >= @val (0, 0, ...
6307 *
6308 * If one object to be compared is a node-set and the other is a number,
6309 * then the comparison will be true if and only if there is a node in the
6310 * node-set such that the result of performing the comparison on the number
6311 * to be compared and on the result of converting the string-value of that
6312 * node to a number using the number function is true.
6313 *
6314 * Returns 0 or 1 depending on the results of the test.
6315 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006316static int
Owen Taylor3473f882001-02-23 17:55:21 +00006317xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6318 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6319 int i, ret = 0;
6320 xmlNodeSetPtr ns;
6321 xmlChar *str2;
6322
6323 if ((f == NULL) || (arg == NULL) ||
6324 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006325 xmlXPathReleaseObject(ctxt->context, arg);
6326 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006327 return(0);
6328 }
6329 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006330 if (ns != NULL) {
6331 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006332 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006333 if (str2 != NULL) {
6334 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006335 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006336 xmlFree(str2);
6337 xmlXPathNumberFunction(ctxt, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006338 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006339 ret = xmlXPathCompareValues(ctxt, inf, strict);
6340 if (ret)
6341 break;
6342 }
6343 }
Owen Taylor3473f882001-02-23 17:55:21 +00006344 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006345 xmlXPathReleaseObject(ctxt->context, arg);
6346 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006347 return(ret);
6348}
6349
6350/**
6351 * xmlXPathCompareNodeSetString:
6352 * @ctxt: the XPath Parser context
6353 * @inf: less than (1) or greater than (0)
6354 * @strict: is the comparison strict
6355 * @arg: the node set
6356 * @s: the value
6357 *
6358 * Implement the compare operation between a nodeset and a string
6359 * @ns < @val (1, 1, ...
6360 * @ns <= @val (1, 0, ...
6361 * @ns > @val (0, 1, ...
6362 * @ns >= @val (0, 0, ...
6363 *
6364 * If one object to be compared is a node-set and the other is a string,
6365 * then the comparison will be true if and only if there is a node in
6366 * the node-set such that the result of performing the comparison on the
6367 * string-value of the node and the other string is true.
6368 *
6369 * Returns 0 or 1 depending on the results of the test.
6370 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006371static int
Owen Taylor3473f882001-02-23 17:55:21 +00006372xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6373 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6374 int i, ret = 0;
6375 xmlNodeSetPtr ns;
6376 xmlChar *str2;
6377
6378 if ((s == NULL) || (arg == NULL) ||
6379 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006380 xmlXPathReleaseObject(ctxt->context, arg);
6381 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006382 return(0);
6383 }
6384 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006385 if (ns != NULL) {
6386 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006387 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006388 if (str2 != NULL) {
6389 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006390 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006391 xmlFree(str2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006392 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006393 ret = xmlXPathCompareValues(ctxt, inf, strict);
6394 if (ret)
6395 break;
6396 }
6397 }
Owen Taylor3473f882001-02-23 17:55:21 +00006398 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006399 xmlXPathReleaseObject(ctxt->context, arg);
6400 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006401 return(ret);
6402}
6403
6404/**
6405 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006406 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00006407 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006408 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00006409 * @arg2: the second node set object
6410 *
6411 * Implement the compare operation on nodesets:
6412 *
6413 * If both objects to be compared are node-sets, then the comparison
6414 * will be true if and only if there is a node in the first node-set
6415 * and a node in the second node-set such that the result of performing
6416 * the comparison on the string-values of the two nodes is true.
6417 * ....
6418 * When neither object to be compared is a node-set and the operator
6419 * is <=, <, >= or >, then the objects are compared by converting both
6420 * objects to numbers and comparing the numbers according to IEEE 754.
6421 * ....
6422 * The number function converts its argument to a number as follows:
6423 * - a string that consists of optional whitespace followed by an
6424 * optional minus sign followed by a Number followed by whitespace
6425 * is converted to the IEEE 754 number that is nearest (according
6426 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6427 * represented by the string; any other string is converted to NaN
6428 *
6429 * Conclusion all nodes need to be converted first to their string value
6430 * and then the comparison must be done when possible
6431 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006432static int
6433xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00006434 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6435 int i, j, init = 0;
6436 double val1;
6437 double *values2;
6438 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006439 xmlNodeSetPtr ns1;
6440 xmlNodeSetPtr ns2;
6441
6442 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006443 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6444 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006445 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006446 }
Owen Taylor3473f882001-02-23 17:55:21 +00006447 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006448 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6449 xmlXPathFreeObject(arg1);
6450 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006451 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006452 }
Owen Taylor3473f882001-02-23 17:55:21 +00006453
6454 ns1 = arg1->nodesetval;
6455 ns2 = arg2->nodesetval;
6456
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006457 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006458 xmlXPathFreeObject(arg1);
6459 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006460 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006461 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006462 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006463 xmlXPathFreeObject(arg1);
6464 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006465 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006466 }
Owen Taylor3473f882001-02-23 17:55:21 +00006467
6468 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6469 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006470 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00006471 xmlXPathFreeObject(arg1);
6472 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006473 return(0);
6474 }
6475 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006476 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00006477 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00006478 continue;
6479 for (j = 0;j < ns2->nodeNr;j++) {
6480 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006481 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00006482 }
Daniel Veillardcda96922001-08-21 10:56:31 +00006483 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00006484 continue;
6485 if (inf && strict)
6486 ret = (val1 < values2[j]);
6487 else if (inf && !strict)
6488 ret = (val1 <= values2[j]);
6489 else if (!inf && strict)
6490 ret = (val1 > values2[j]);
6491 else if (!inf && !strict)
6492 ret = (val1 >= values2[j]);
6493 if (ret)
6494 break;
6495 }
6496 if (ret)
6497 break;
6498 init = 1;
6499 }
6500 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006501 xmlXPathFreeObject(arg1);
6502 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006503 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006504}
6505
6506/**
6507 * xmlXPathCompareNodeSetValue:
6508 * @ctxt: the XPath Parser context
6509 * @inf: less than (1) or greater than (0)
6510 * @strict: is the comparison strict
6511 * @arg: the node set
6512 * @val: the value
6513 *
6514 * Implement the compare operation between a nodeset and a value
6515 * @ns < @val (1, 1, ...
6516 * @ns <= @val (1, 0, ...
6517 * @ns > @val (0, 1, ...
6518 * @ns >= @val (0, 0, ...
6519 *
6520 * If one object to be compared is a node-set and the other is a boolean,
6521 * then the comparison will be true if and only if the result of performing
6522 * the comparison on the boolean and on the result of converting
6523 * the node-set to a boolean using the boolean function is true.
6524 *
6525 * Returns 0 or 1 depending on the results of the test.
6526 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006527static int
Owen Taylor3473f882001-02-23 17:55:21 +00006528xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6529 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6530 if ((val == NULL) || (arg == NULL) ||
6531 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6532 return(0);
6533
6534 switch(val->type) {
6535 case XPATH_NUMBER:
6536 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6537 case XPATH_NODESET:
6538 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006539 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00006540 case XPATH_STRING:
6541 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6542 case XPATH_BOOLEAN:
6543 valuePush(ctxt, arg);
6544 xmlXPathBooleanFunction(ctxt, 1);
6545 valuePush(ctxt, val);
6546 return(xmlXPathCompareValues(ctxt, inf, strict));
6547 default:
6548 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00006549 }
6550 return(0);
6551}
6552
6553/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006554 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00006555 * @arg: the nodeset object argument
6556 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00006557 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006558 *
6559 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6560 * If one object to be compared is a node-set and the other is a string,
6561 * then the comparison will be true if and only if there is a node in
6562 * the node-set such that the result of performing the comparison on the
6563 * string-value of the node and the other string is true.
6564 *
6565 * Returns 0 or 1 depending on the results of the test.
6566 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006567static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006568xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006569{
Owen Taylor3473f882001-02-23 17:55:21 +00006570 int i;
6571 xmlNodeSetPtr ns;
6572 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006573 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00006574
6575 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00006576 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6577 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006578 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00006579 /*
6580 * A NULL nodeset compared with a string is always false
6581 * (since there is no node equal, and no node not equal)
6582 */
6583 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00006584 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00006585 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006586 for (i = 0; i < ns->nodeNr; i++) {
6587 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6588 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6589 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6590 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006591 if (neq)
6592 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006593 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00006594 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6595 if (neq)
6596 continue;
6597 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006598 } else if (neq) {
6599 if (str2 != NULL)
6600 xmlFree(str2);
6601 return (1);
6602 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006603 if (str2 != NULL)
6604 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006605 } else if (neq)
6606 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00006607 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006608 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006609}
6610
6611/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006612 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00006613 * @arg: the nodeset object argument
6614 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00006615 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006616 *
6617 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6618 * If one object to be compared is a node-set and the other is a number,
6619 * then the comparison will be true if and only if there is a node in
6620 * the node-set such that the result of performing the comparison on the
6621 * number to be compared and on the result of converting the string-value
6622 * of that node to a number using the number function is true.
6623 *
6624 * Returns 0 or 1 depending on the results of the test.
6625 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006626static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006627xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6628 xmlXPathObjectPtr arg, double f, int neq) {
6629 int i, ret=0;
6630 xmlNodeSetPtr ns;
6631 xmlChar *str2;
6632 xmlXPathObjectPtr val;
6633 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00006634
6635 if ((arg == NULL) ||
6636 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6637 return(0);
6638
William M. Brack0c022ad2002-07-12 00:56:01 +00006639 ns = arg->nodesetval;
6640 if (ns != NULL) {
6641 for (i=0;i<ns->nodeNr;i++) {
6642 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6643 if (str2 != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006644 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
William M. Brack0c022ad2002-07-12 00:56:01 +00006645 xmlFree(str2);
6646 xmlXPathNumberFunction(ctxt, 1);
6647 val = valuePop(ctxt);
6648 v = val->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006649 xmlXPathReleaseObject(ctxt->context, val);
William M. Brack0c022ad2002-07-12 00:56:01 +00006650 if (!xmlXPathIsNaN(v)) {
6651 if ((!neq) && (v==f)) {
6652 ret = 1;
6653 break;
6654 } else if ((neq) && (v!=f)) {
6655 ret = 1;
6656 break;
6657 }
William M. Brack32f0f712005-07-14 07:00:33 +00006658 } else { /* NaN is unequal to any value */
6659 if (neq)
6660 ret = 1;
William M. Brack0c022ad2002-07-12 00:56:01 +00006661 }
6662 }
6663 }
6664 }
6665
6666 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006667}
6668
6669
6670/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006671 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00006672 * @arg1: first nodeset object argument
6673 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00006674 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006675 *
William M. Brack0c022ad2002-07-12 00:56:01 +00006676 * Implement the equal / not equal operation on XPath nodesets:
6677 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00006678 * If both objects to be compared are node-sets, then the comparison
6679 * will be true if and only if there is a node in the first node-set and
6680 * a node in the second node-set such that the result of performing the
6681 * comparison on the string-values of the two nodes is true.
6682 *
6683 * (needless to say, this is a costly operation)
6684 *
6685 * Returns 0 or 1 depending on the results of the test.
6686 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006687static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006688xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00006689 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006690 unsigned int *hashs1;
6691 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00006692 xmlChar **values1;
6693 xmlChar **values2;
6694 int ret = 0;
6695 xmlNodeSetPtr ns1;
6696 xmlNodeSetPtr ns2;
6697
6698 if ((arg1 == NULL) ||
6699 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6700 return(0);
6701 if ((arg2 == NULL) ||
6702 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6703 return(0);
6704
6705 ns1 = arg1->nodesetval;
6706 ns2 = arg2->nodesetval;
6707
Daniel Veillard911f49a2001-04-07 15:39:35 +00006708 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006709 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006710 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006711 return(0);
6712
6713 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00006714 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00006715 */
William M. Brack0c022ad2002-07-12 00:56:01 +00006716 if (neq == 0)
6717 for (i = 0;i < ns1->nodeNr;i++)
6718 for (j = 0;j < ns2->nodeNr;j++)
6719 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6720 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006721
6722 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006723 if (values1 == NULL) {
6724 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006725 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006726 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006727 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6728 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006729 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006730 xmlFree(values1);
6731 return(0);
6732 }
Owen Taylor3473f882001-02-23 17:55:21 +00006733 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6734 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6735 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006736 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006737 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00006738 xmlFree(values1);
6739 return(0);
6740 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006741 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6742 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006743 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006744 xmlFree(hashs1);
6745 xmlFree(values1);
6746 xmlFree(values2);
6747 return(0);
6748 }
Owen Taylor3473f882001-02-23 17:55:21 +00006749 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6750 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006751 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006752 for (j = 0;j < ns2->nodeNr;j++) {
6753 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006754 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006755 if (hashs1[i] != hashs2[j]) {
6756 if (neq) {
6757 ret = 1;
6758 break;
6759 }
6760 }
6761 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006762 if (values1[i] == NULL)
6763 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6764 if (values2[j] == NULL)
6765 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006766 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006767 if (ret)
6768 break;
6769 }
Owen Taylor3473f882001-02-23 17:55:21 +00006770 }
6771 if (ret)
6772 break;
6773 }
6774 for (i = 0;i < ns1->nodeNr;i++)
6775 if (values1[i] != NULL)
6776 xmlFree(values1[i]);
6777 for (j = 0;j < ns2->nodeNr;j++)
6778 if (values2[j] != NULL)
6779 xmlFree(values2[j]);
6780 xmlFree(values1);
6781 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006782 xmlFree(hashs1);
6783 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00006784 return(ret);
6785}
6786
William M. Brack0c022ad2002-07-12 00:56:01 +00006787static int
6788xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6789 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00006790 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00006791 /*
6792 *At this point we are assured neither arg1 nor arg2
6793 *is a nodeset, so we can just pick the appropriate routine.
6794 */
Owen Taylor3473f882001-02-23 17:55:21 +00006795 switch (arg1->type) {
6796 case XPATH_UNDEFINED:
6797#ifdef DEBUG_EXPR
6798 xmlGenericError(xmlGenericErrorContext,
6799 "Equal: undefined\n");
6800#endif
6801 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006802 case XPATH_BOOLEAN:
6803 switch (arg2->type) {
6804 case XPATH_UNDEFINED:
6805#ifdef DEBUG_EXPR
6806 xmlGenericError(xmlGenericErrorContext,
6807 "Equal: undefined\n");
6808#endif
6809 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006810 case XPATH_BOOLEAN:
6811#ifdef DEBUG_EXPR
6812 xmlGenericError(xmlGenericErrorContext,
6813 "Equal: %d boolean %d \n",
6814 arg1->boolval, arg2->boolval);
6815#endif
6816 ret = (arg1->boolval == arg2->boolval);
6817 break;
6818 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00006819 ret = (arg1->boolval ==
6820 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006821 break;
6822 case XPATH_STRING:
6823 if ((arg2->stringval == NULL) ||
6824 (arg2->stringval[0] == 0)) ret = 0;
6825 else
6826 ret = 1;
6827 ret = (arg1->boolval == ret);
6828 break;
6829 case XPATH_USERS:
6830 case XPATH_POINT:
6831 case XPATH_RANGE:
6832 case XPATH_LOCATIONSET:
6833 TODO
6834 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006835 case XPATH_NODESET:
6836 case XPATH_XSLT_TREE:
6837 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006838 }
6839 break;
6840 case XPATH_NUMBER:
6841 switch (arg2->type) {
6842 case XPATH_UNDEFINED:
6843#ifdef DEBUG_EXPR
6844 xmlGenericError(xmlGenericErrorContext,
6845 "Equal: undefined\n");
6846#endif
6847 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006848 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00006849 ret = (arg2->boolval==
6850 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006851 break;
6852 case XPATH_STRING:
6853 valuePush(ctxt, arg2);
6854 xmlXPathNumberFunction(ctxt, 1);
6855 arg2 = valuePop(ctxt);
6856 /* no break on purpose */
6857 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006858 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00006859 if (xmlXPathIsNaN(arg1->floatval) ||
6860 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00006861 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006862 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6863 if (xmlXPathIsInf(arg2->floatval) == 1)
6864 ret = 1;
6865 else
6866 ret = 0;
6867 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6868 if (xmlXPathIsInf(arg2->floatval) == -1)
6869 ret = 1;
6870 else
6871 ret = 0;
6872 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6873 if (xmlXPathIsInf(arg1->floatval) == 1)
6874 ret = 1;
6875 else
6876 ret = 0;
6877 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6878 if (xmlXPathIsInf(arg1->floatval) == -1)
6879 ret = 1;
6880 else
6881 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00006882 } else {
6883 ret = (arg1->floatval == arg2->floatval);
6884 }
Owen Taylor3473f882001-02-23 17:55:21 +00006885 break;
6886 case XPATH_USERS:
6887 case XPATH_POINT:
6888 case XPATH_RANGE:
6889 case XPATH_LOCATIONSET:
6890 TODO
6891 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006892 case XPATH_NODESET:
6893 case XPATH_XSLT_TREE:
6894 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006895 }
6896 break;
6897 case XPATH_STRING:
6898 switch (arg2->type) {
6899 case XPATH_UNDEFINED:
6900#ifdef DEBUG_EXPR
6901 xmlGenericError(xmlGenericErrorContext,
6902 "Equal: undefined\n");
6903#endif
6904 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006905 case XPATH_BOOLEAN:
6906 if ((arg1->stringval == NULL) ||
6907 (arg1->stringval[0] == 0)) ret = 0;
6908 else
6909 ret = 1;
6910 ret = (arg2->boolval == ret);
6911 break;
6912 case XPATH_STRING:
6913 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6914 break;
6915 case XPATH_NUMBER:
6916 valuePush(ctxt, arg1);
6917 xmlXPathNumberFunction(ctxt, 1);
6918 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006919 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00006920 if (xmlXPathIsNaN(arg1->floatval) ||
6921 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00006922 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006923 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6924 if (xmlXPathIsInf(arg2->floatval) == 1)
6925 ret = 1;
6926 else
6927 ret = 0;
6928 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6929 if (xmlXPathIsInf(arg2->floatval) == -1)
6930 ret = 1;
6931 else
6932 ret = 0;
6933 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6934 if (xmlXPathIsInf(arg1->floatval) == 1)
6935 ret = 1;
6936 else
6937 ret = 0;
6938 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6939 if (xmlXPathIsInf(arg1->floatval) == -1)
6940 ret = 1;
6941 else
6942 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00006943 } else {
6944 ret = (arg1->floatval == arg2->floatval);
6945 }
Owen Taylor3473f882001-02-23 17:55:21 +00006946 break;
6947 case XPATH_USERS:
6948 case XPATH_POINT:
6949 case XPATH_RANGE:
6950 case XPATH_LOCATIONSET:
6951 TODO
6952 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006953 case XPATH_NODESET:
6954 case XPATH_XSLT_TREE:
6955 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006956 }
6957 break;
6958 case XPATH_USERS:
6959 case XPATH_POINT:
6960 case XPATH_RANGE:
6961 case XPATH_LOCATIONSET:
6962 TODO
6963 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006964 case XPATH_NODESET:
6965 case XPATH_XSLT_TREE:
6966 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006967 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006968 xmlXPathReleaseObject(ctxt->context, arg1);
6969 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006970 return(ret);
6971}
6972
William M. Brack0c022ad2002-07-12 00:56:01 +00006973/**
6974 * xmlXPathEqualValues:
6975 * @ctxt: the XPath Parser context
6976 *
6977 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6978 *
6979 * Returns 0 or 1 depending on the results of the test.
6980 */
6981int
6982xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
6983 xmlXPathObjectPtr arg1, arg2, argtmp;
6984 int ret = 0;
6985
Daniel Veillard6128c012004-11-08 17:16:15 +00006986 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00006987 arg2 = valuePop(ctxt);
6988 arg1 = valuePop(ctxt);
6989 if ((arg1 == NULL) || (arg2 == NULL)) {
6990 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006991 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006992 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006993 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006994 XP_ERROR0(XPATH_INVALID_OPERAND);
6995 }
6996
6997 if (arg1 == arg2) {
6998#ifdef DEBUG_EXPR
6999 xmlGenericError(xmlGenericErrorContext,
7000 "Equal: by pointer\n");
7001#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00007002 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007003 return(1);
7004 }
7005
7006 /*
7007 *If either argument is a nodeset, it's a 'special case'
7008 */
7009 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7010 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7011 /*
7012 *Hack it to assure arg1 is the nodeset
7013 */
7014 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7015 argtmp = arg2;
7016 arg2 = arg1;
7017 arg1 = argtmp;
7018 }
7019 switch (arg2->type) {
7020 case XPATH_UNDEFINED:
7021#ifdef DEBUG_EXPR
7022 xmlGenericError(xmlGenericErrorContext,
7023 "Equal: undefined\n");
7024#endif
7025 break;
7026 case XPATH_NODESET:
7027 case XPATH_XSLT_TREE:
7028 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7029 break;
7030 case XPATH_BOOLEAN:
7031 if ((arg1->nodesetval == NULL) ||
7032 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7033 else
7034 ret = 1;
7035 ret = (ret == arg2->boolval);
7036 break;
7037 case XPATH_NUMBER:
7038 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7039 break;
7040 case XPATH_STRING:
7041 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7042 break;
7043 case XPATH_USERS:
7044 case XPATH_POINT:
7045 case XPATH_RANGE:
7046 case XPATH_LOCATIONSET:
7047 TODO
7048 break;
7049 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007050 xmlXPathReleaseObject(ctxt->context, arg1);
7051 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007052 return(ret);
7053 }
7054
7055 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7056}
7057
7058/**
7059 * xmlXPathNotEqualValues:
7060 * @ctxt: the XPath Parser context
7061 *
7062 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7063 *
7064 * Returns 0 or 1 depending on the results of the test.
7065 */
7066int
7067xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7068 xmlXPathObjectPtr arg1, arg2, argtmp;
7069 int ret = 0;
7070
Daniel Veillard6128c012004-11-08 17:16:15 +00007071 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00007072 arg2 = valuePop(ctxt);
7073 arg1 = valuePop(ctxt);
7074 if ((arg1 == NULL) || (arg2 == NULL)) {
7075 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007076 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007077 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007078 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007079 XP_ERROR0(XPATH_INVALID_OPERAND);
7080 }
7081
7082 if (arg1 == arg2) {
7083#ifdef DEBUG_EXPR
7084 xmlGenericError(xmlGenericErrorContext,
7085 "NotEqual: by pointer\n");
7086#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007087 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007088 return(0);
7089 }
7090
7091 /*
7092 *If either argument is a nodeset, it's a 'special case'
7093 */
7094 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7095 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7096 /*
7097 *Hack it to assure arg1 is the nodeset
7098 */
7099 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7100 argtmp = arg2;
7101 arg2 = arg1;
7102 arg1 = argtmp;
7103 }
7104 switch (arg2->type) {
7105 case XPATH_UNDEFINED:
7106#ifdef DEBUG_EXPR
7107 xmlGenericError(xmlGenericErrorContext,
7108 "NotEqual: undefined\n");
7109#endif
7110 break;
7111 case XPATH_NODESET:
7112 case XPATH_XSLT_TREE:
7113 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7114 break;
7115 case XPATH_BOOLEAN:
7116 if ((arg1->nodesetval == NULL) ||
7117 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7118 else
7119 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00007120 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00007121 break;
7122 case XPATH_NUMBER:
7123 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7124 break;
7125 case XPATH_STRING:
7126 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7127 break;
7128 case XPATH_USERS:
7129 case XPATH_POINT:
7130 case XPATH_RANGE:
7131 case XPATH_LOCATIONSET:
7132 TODO
7133 break;
7134 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007135 xmlXPathReleaseObject(ctxt->context, arg1);
7136 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007137 return(ret);
7138 }
7139
7140 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7141}
Owen Taylor3473f882001-02-23 17:55:21 +00007142
7143/**
7144 * xmlXPathCompareValues:
7145 * @ctxt: the XPath Parser context
7146 * @inf: less than (1) or greater than (0)
7147 * @strict: is the comparison strict
7148 *
7149 * Implement the compare operation on XPath objects:
7150 * @arg1 < @arg2 (1, 1, ...
7151 * @arg1 <= @arg2 (1, 0, ...
7152 * @arg1 > @arg2 (0, 1, ...
7153 * @arg1 >= @arg2 (0, 0, ...
7154 *
7155 * When neither object to be compared is a node-set and the operator is
7156 * <=, <, >=, >, then the objects are compared by converted both objects
7157 * to numbers and comparing the numbers according to IEEE 754. The <
7158 * comparison will be true if and only if the first number is less than the
7159 * second number. The <= comparison will be true if and only if the first
7160 * number is less than or equal to the second number. The > comparison
7161 * will be true if and only if the first number is greater than the second
7162 * number. The >= comparison will be true if and only if the first number
7163 * is greater than or equal to the second number.
7164 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007165 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00007166 */
7167int
7168xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007169 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007170 xmlXPathObjectPtr arg1, arg2;
7171
Daniel Veillard6128c012004-11-08 17:16:15 +00007172 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00007173 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007174 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007175 if ((arg1 == NULL) || (arg2 == NULL)) {
7176 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007177 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007178 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007179 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007180 XP_ERROR0(XPATH_INVALID_OPERAND);
7181 }
7182
William M. Brack0c022ad2002-07-12 00:56:01 +00007183 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7184 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
William M. Brackd6e347e2005-04-15 01:34:41 +00007185 /*
7186 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7187 * are not freed from within this routine; they will be freed from the
7188 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7189 */
William M. Brack0c022ad2002-07-12 00:56:01 +00007190 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7191 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007192 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007193 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00007194 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007195 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7196 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007197 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007198 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7199 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00007200 }
7201 }
7202 return(ret);
7203 }
7204
7205 if (arg1->type != XPATH_NUMBER) {
7206 valuePush(ctxt, arg1);
7207 xmlXPathNumberFunction(ctxt, 1);
7208 arg1 = valuePop(ctxt);
7209 }
7210 if (arg1->type != XPATH_NUMBER) {
7211 xmlXPathFreeObject(arg1);
7212 xmlXPathFreeObject(arg2);
7213 XP_ERROR0(XPATH_INVALID_OPERAND);
7214 }
7215 if (arg2->type != XPATH_NUMBER) {
7216 valuePush(ctxt, arg2);
7217 xmlXPathNumberFunction(ctxt, 1);
7218 arg2 = valuePop(ctxt);
7219 }
7220 if (arg2->type != XPATH_NUMBER) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007221 xmlXPathReleaseObject(ctxt->context, arg1);
7222 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007223 XP_ERROR0(XPATH_INVALID_OPERAND);
7224 }
7225 /*
7226 * Add tests for infinity and nan
7227 * => feedback on 3.4 for Inf and NaN
7228 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007229 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00007230 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007231 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007232 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007233 arg1i=xmlXPathIsInf(arg1->floatval);
7234 arg2i=xmlXPathIsInf(arg2->floatval);
7235 if (inf && strict) {
7236 if ((arg1i == -1 && arg2i != -1) ||
7237 (arg2i == 1 && arg1i != 1)) {
7238 ret = 1;
7239 } else if (arg1i == 0 && arg2i == 0) {
7240 ret = (arg1->floatval < arg2->floatval);
7241 } else {
7242 ret = 0;
7243 }
7244 }
7245 else if (inf && !strict) {
7246 if (arg1i == -1 || arg2i == 1) {
7247 ret = 1;
7248 } else if (arg1i == 0 && arg2i == 0) {
7249 ret = (arg1->floatval <= arg2->floatval);
7250 } else {
7251 ret = 0;
7252 }
7253 }
7254 else if (!inf && strict) {
7255 if ((arg1i == 1 && arg2i != 1) ||
7256 (arg2i == -1 && arg1i != -1)) {
7257 ret = 1;
7258 } else if (arg1i == 0 && arg2i == 0) {
7259 ret = (arg1->floatval > arg2->floatval);
7260 } else {
7261 ret = 0;
7262 }
7263 }
7264 else if (!inf && !strict) {
7265 if (arg1i == 1 || arg2i == -1) {
7266 ret = 1;
7267 } else if (arg1i == 0 && arg2i == 0) {
7268 ret = (arg1->floatval >= arg2->floatval);
7269 } else {
7270 ret = 0;
7271 }
7272 }
Daniel Veillard21458c82002-03-27 16:12:22 +00007273 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007274 xmlXPathReleaseObject(ctxt->context, arg1);
7275 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007276 return(ret);
7277}
7278
7279/**
7280 * xmlXPathValueFlipSign:
7281 * @ctxt: the XPath Parser context
7282 *
7283 * Implement the unary - operation on an XPath object
7284 * The numeric operators convert their operands to numbers as if
7285 * by calling the number function.
7286 */
7287void
7288xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007289 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007290 CAST_TO_NUMBER;
7291 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007292 if (xmlXPathIsNaN(ctxt->value->floatval))
7293 ctxt->value->floatval=xmlXPathNAN;
7294 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7295 ctxt->value->floatval=xmlXPathNINF;
7296 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7297 ctxt->value->floatval=xmlXPathPINF;
7298 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007299 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7300 ctxt->value->floatval = xmlXPathNZERO;
7301 else
7302 ctxt->value->floatval = 0;
7303 }
7304 else
7305 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00007306}
7307
7308/**
7309 * xmlXPathAddValues:
7310 * @ctxt: the XPath Parser context
7311 *
7312 * Implement the add operation on XPath objects:
7313 * The numeric operators convert their operands to numbers as if
7314 * by calling the number function.
7315 */
7316void
7317xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7318 xmlXPathObjectPtr arg;
7319 double val;
7320
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007321 arg = valuePop(ctxt);
7322 if (arg == NULL)
7323 XP_ERROR(XPATH_INVALID_OPERAND);
7324 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007325 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007326 CAST_TO_NUMBER;
7327 CHECK_TYPE(XPATH_NUMBER);
7328 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00007329}
7330
7331/**
7332 * xmlXPathSubValues:
7333 * @ctxt: the XPath Parser context
7334 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007335 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007336 * The numeric operators convert their operands to numbers as if
7337 * by calling the number function.
7338 */
7339void
7340xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7341 xmlXPathObjectPtr arg;
7342 double val;
7343
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007344 arg = valuePop(ctxt);
7345 if (arg == NULL)
7346 XP_ERROR(XPATH_INVALID_OPERAND);
7347 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007348 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007349 CAST_TO_NUMBER;
7350 CHECK_TYPE(XPATH_NUMBER);
7351 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007352}
7353
7354/**
7355 * xmlXPathMultValues:
7356 * @ctxt: the XPath Parser context
7357 *
7358 * Implement the multiply operation on XPath objects:
7359 * The numeric operators convert their operands to numbers as if
7360 * by calling the number function.
7361 */
7362void
7363xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7364 xmlXPathObjectPtr arg;
7365 double val;
7366
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007367 arg = valuePop(ctxt);
7368 if (arg == NULL)
7369 XP_ERROR(XPATH_INVALID_OPERAND);
7370 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007371 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007372 CAST_TO_NUMBER;
7373 CHECK_TYPE(XPATH_NUMBER);
7374 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007375}
7376
7377/**
7378 * xmlXPathDivValues:
7379 * @ctxt: the XPath Parser context
7380 *
7381 * Implement the div operation on XPath objects @arg1 / @arg2:
7382 * The numeric operators convert their operands to numbers as if
7383 * by calling the number function.
7384 */
7385void
7386xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7387 xmlXPathObjectPtr arg;
7388 double val;
7389
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007390 arg = valuePop(ctxt);
7391 if (arg == NULL)
7392 XP_ERROR(XPATH_INVALID_OPERAND);
7393 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007394 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007395 CAST_TO_NUMBER;
7396 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007397 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7398 ctxt->value->floatval = xmlXPathNAN;
7399 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007400 if (ctxt->value->floatval == 0)
7401 ctxt->value->floatval = xmlXPathNAN;
7402 else if (ctxt->value->floatval > 0)
7403 ctxt->value->floatval = xmlXPathNINF;
7404 else if (ctxt->value->floatval < 0)
7405 ctxt->value->floatval = xmlXPathPINF;
7406 }
7407 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007408 if (ctxt->value->floatval == 0)
7409 ctxt->value->floatval = xmlXPathNAN;
7410 else if (ctxt->value->floatval > 0)
7411 ctxt->value->floatval = xmlXPathPINF;
7412 else if (ctxt->value->floatval < 0)
7413 ctxt->value->floatval = xmlXPathNINF;
7414 } else
7415 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007416}
7417
7418/**
7419 * xmlXPathModValues:
7420 * @ctxt: the XPath Parser context
7421 *
7422 * Implement the mod operation on XPath objects: @arg1 / @arg2
7423 * The numeric operators convert their operands to numbers as if
7424 * by calling the number function.
7425 */
7426void
7427xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7428 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00007429 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00007430
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007431 arg = valuePop(ctxt);
7432 if (arg == NULL)
7433 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007434 arg2 = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007435 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007436 CAST_TO_NUMBER;
7437 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007438 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00007439 if (arg2 == 0)
7440 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007441 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00007442 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007443 }
Owen Taylor3473f882001-02-23 17:55:21 +00007444}
7445
7446/************************************************************************
7447 * *
7448 * The traversal functions *
7449 * *
7450 ************************************************************************/
7451
Owen Taylor3473f882001-02-23 17:55:21 +00007452/*
7453 * A traversal function enumerates nodes along an axis.
7454 * Initially it must be called with NULL, and it indicates
7455 * termination on the axis by returning NULL.
7456 */
7457typedef xmlNodePtr (*xmlXPathTraversalFunction)
7458 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7459
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007460/*
7461 * xmlXPathTraversalFunctionExt:
7462 * A traversal function enumerates nodes along an axis.
7463 * Initially it must be called with NULL, and it indicates
7464 * termination on the axis by returning NULL.
7465 * The context node of the traversal is specified via @contextNode.
7466 */
7467typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7468 (xmlNodePtr cur, xmlNodePtr contextNode);
7469
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00007470/*
7471 * xmlXPathNodeSetMergeFunction:
7472 * Used for merging node sets in xmlXPathCollectAndTest().
7473 */
7474typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7475 (xmlNodeSetPtr, xmlNodeSetPtr, int);
7476
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007477
Owen Taylor3473f882001-02-23 17:55:21 +00007478/**
7479 * xmlXPathNextSelf:
7480 * @ctxt: the XPath Parser context
7481 * @cur: the current node in the traversal
7482 *
7483 * Traversal function for the "self" direction
7484 * The self axis contains just the context node itself
7485 *
7486 * Returns the next element following that axis
7487 */
7488xmlNodePtr
7489xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007490 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007491 if (cur == NULL)
7492 return(ctxt->context->node);
7493 return(NULL);
7494}
7495
7496/**
7497 * xmlXPathNextChild:
7498 * @ctxt: the XPath Parser context
7499 * @cur: the current node in the traversal
7500 *
7501 * Traversal function for the "child" direction
7502 * The child axis contains the children of the context node in document order.
7503 *
7504 * Returns the next element following that axis
7505 */
7506xmlNodePtr
7507xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007508 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007509 if (cur == NULL) {
7510 if (ctxt->context->node == NULL) return(NULL);
7511 switch (ctxt->context->node->type) {
7512 case XML_ELEMENT_NODE:
7513 case XML_TEXT_NODE:
7514 case XML_CDATA_SECTION_NODE:
7515 case XML_ENTITY_REF_NODE:
7516 case XML_ENTITY_NODE:
7517 case XML_PI_NODE:
7518 case XML_COMMENT_NODE:
7519 case XML_NOTATION_NODE:
7520 case XML_DTD_NODE:
7521 return(ctxt->context->node->children);
7522 case XML_DOCUMENT_NODE:
7523 case XML_DOCUMENT_TYPE_NODE:
7524 case XML_DOCUMENT_FRAG_NODE:
7525 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007526#ifdef LIBXML_DOCB_ENABLED
7527 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007528#endif
7529 return(((xmlDocPtr) ctxt->context->node)->children);
7530 case XML_ELEMENT_DECL:
7531 case XML_ATTRIBUTE_DECL:
7532 case XML_ENTITY_DECL:
7533 case XML_ATTRIBUTE_NODE:
7534 case XML_NAMESPACE_DECL:
7535 case XML_XINCLUDE_START:
7536 case XML_XINCLUDE_END:
7537 return(NULL);
7538 }
7539 return(NULL);
7540 }
7541 if ((cur->type == XML_DOCUMENT_NODE) ||
7542 (cur->type == XML_HTML_DOCUMENT_NODE))
7543 return(NULL);
7544 return(cur->next);
7545}
7546
7547/**
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00007548 * xmlXPathNextChildElement:
7549 * @ctxt: the XPath Parser context
7550 * @cur: the current node in the traversal
7551 *
7552 * Traversal function for the "child" direction and nodes of type element.
7553 * The child axis contains the children of the context node in document order.
7554 *
7555 * Returns the next element following that axis
7556 */
7557static xmlNodePtr
7558xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7559 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7560 if (cur == NULL) {
7561 cur = ctxt->context->node;
7562 if (cur == NULL) return(NULL);
7563 /*
7564 * Get the first element child.
7565 */
7566 switch (cur->type) {
7567 case XML_ELEMENT_NODE:
7568 case XML_DOCUMENT_FRAG_NODE:
7569 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7570 case XML_ENTITY_NODE:
7571 cur = cur->children;
7572 if (cur != NULL) {
7573 if (cur->type == XML_ELEMENT_NODE)
7574 return(cur);
7575 do {
7576 cur = cur->next;
7577 } while ((cur != NULL) &&
7578 (cur->type != XML_ELEMENT_NODE));
7579 return(cur);
7580 }
7581 return(NULL);
7582 case XML_DOCUMENT_NODE:
7583 case XML_HTML_DOCUMENT_NODE:
7584#ifdef LIBXML_DOCB_ENABLED
7585 case XML_DOCB_DOCUMENT_NODE:
7586#endif
7587 return(xmlDocGetRootElement((xmlDocPtr) cur));
7588 default:
7589 return(NULL);
7590 }
7591 return(NULL);
7592 }
7593 /*
7594 * Get the next sibling element node.
7595 */
7596 switch (cur->type) {
7597 case XML_ELEMENT_NODE:
7598 case XML_TEXT_NODE:
7599 case XML_ENTITY_REF_NODE:
7600 case XML_ENTITY_NODE:
7601 case XML_CDATA_SECTION_NODE:
7602 case XML_PI_NODE:
7603 case XML_COMMENT_NODE:
7604 case XML_XINCLUDE_END:
7605 break;
7606 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7607 default:
7608 return(NULL);
7609 }
7610 if (cur->next != NULL) {
7611 if (cur->next->type == XML_ELEMENT_NODE)
7612 return(cur->next);
7613 cur = cur->next;
7614 do {
7615 cur = cur->next;
7616 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7617 return(cur);
7618 }
7619 return(NULL);
7620}
7621
7622/**
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007623 * xmlXPathNextDescendantOrSelfElemParent:
7624 * @ctxt: the XPath Parser context
7625 * @cur: the current node in the traversal
7626 *
7627 * Traversal function for the "descendant-or-self" axis.
7628 * Additionally it returns only nodes which can be parents of
7629 * element nodes.
7630 *
7631 *
7632 * Returns the next element following that axis
7633 */
7634static xmlNodePtr
7635xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7636 xmlNodePtr contextNode)
7637{
7638 if (cur == NULL) {
7639 if (contextNode == NULL)
7640 return(NULL);
7641 switch (contextNode->type) {
7642 case XML_ELEMENT_NODE:
7643 case XML_XINCLUDE_START:
7644 case XML_DOCUMENT_FRAG_NODE:
7645 case XML_DOCUMENT_NODE:
7646#ifdef LIBXML_DOCB_ENABLED
7647 case XML_DOCB_DOCUMENT_NODE:
7648#endif
7649 case XML_HTML_DOCUMENT_NODE:
7650 return(contextNode);
7651 default:
7652 return(NULL);
7653 }
7654 return(NULL);
7655 } else {
7656 xmlNodePtr start = cur;
7657
7658 while (cur != NULL) {
7659 switch (cur->type) {
7660 case XML_ELEMENT_NODE:
7661 /* TODO: OK to have XInclude here? */
7662 case XML_XINCLUDE_START:
7663 case XML_DOCUMENT_FRAG_NODE:
7664 if (cur != start)
7665 return(cur);
7666 if (cur->children != NULL) {
7667 cur = cur->children;
7668 continue;
7669 }
7670 break;
7671#ifdef LIBXML_DOCB_ENABLED
7672 /* Not sure if we need those here. */
7673 case XML_DOCUMENT_NODE:
7674 case XML_DOCB_DOCUMENT_NODE:
7675#endif
7676 case XML_HTML_DOCUMENT_NODE:
7677 if (cur != start)
7678 return(cur);
7679 return(xmlDocGetRootElement((xmlDocPtr) cur));
7680 default:
7681 break;
7682 }
7683
7684next_sibling:
7685 if ((cur == NULL) || (cur == contextNode))
7686 return(NULL);
7687 if (cur->next != NULL) {
7688 cur = cur->next;
7689 } else {
7690 cur = cur->parent;
7691 goto next_sibling;
7692 }
7693 }
7694 }
7695 return(NULL);
7696}
7697
7698/**
Owen Taylor3473f882001-02-23 17:55:21 +00007699 * xmlXPathNextDescendant:
7700 * @ctxt: the XPath Parser context
7701 * @cur: the current node in the traversal
7702 *
7703 * Traversal function for the "descendant" direction
7704 * the descendant axis contains the descendants of the context node in document
7705 * order; a descendant is a child or a child of a child and so on.
7706 *
7707 * Returns the next element following that axis
7708 */
7709xmlNodePtr
7710xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007711 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007712 if (cur == NULL) {
7713 if (ctxt->context->node == NULL)
7714 return(NULL);
7715 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7716 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7717 return(NULL);
7718
7719 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7720 return(ctxt->context->doc->children);
7721 return(ctxt->context->node->children);
7722 }
7723
Daniel Veillard567e1b42001-08-01 15:53:47 +00007724 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007725 /*
7726 * Do not descend on entities declarations
7727 */
7728 if (cur->children->type != XML_ENTITY_DECL) {
7729 cur = cur->children;
7730 /*
7731 * Skip DTDs
7732 */
7733 if (cur->type != XML_DTD_NODE)
7734 return(cur);
7735 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00007736 }
7737
7738 if (cur == ctxt->context->node) return(NULL);
7739
Daniel Veillard68e9e742002-11-16 15:35:11 +00007740 while (cur->next != NULL) {
7741 cur = cur->next;
7742 if ((cur->type != XML_ENTITY_DECL) &&
7743 (cur->type != XML_DTD_NODE))
7744 return(cur);
7745 }
Owen Taylor3473f882001-02-23 17:55:21 +00007746
7747 do {
7748 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00007749 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00007750 if (cur == ctxt->context->node) return(NULL);
7751 if (cur->next != NULL) {
7752 cur = cur->next;
7753 return(cur);
7754 }
7755 } while (cur != NULL);
7756 return(cur);
7757}
7758
7759/**
7760 * xmlXPathNextDescendantOrSelf:
7761 * @ctxt: the XPath Parser context
7762 * @cur: the current node in the traversal
7763 *
7764 * Traversal function for the "descendant-or-self" direction
7765 * the descendant-or-self axis contains the context node and the descendants
7766 * of the context node in document order; thus the context node is the first
7767 * node on the axis, and the first child of the context node is the second node
7768 * on the axis
7769 *
7770 * Returns the next element following that axis
7771 */
7772xmlNodePtr
7773xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007774 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007775 if (cur == NULL) {
7776 if (ctxt->context->node == NULL)
7777 return(NULL);
7778 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7779 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7780 return(NULL);
7781 return(ctxt->context->node);
7782 }
7783
7784 return(xmlXPathNextDescendant(ctxt, cur));
7785}
7786
7787/**
7788 * xmlXPathNextParent:
7789 * @ctxt: the XPath Parser context
7790 * @cur: the current node in the traversal
7791 *
7792 * Traversal function for the "parent" direction
7793 * The parent axis contains the parent of the context node, if there is one.
7794 *
7795 * Returns the next element following that axis
7796 */
7797xmlNodePtr
7798xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007799 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007800 /*
7801 * the parent of an attribute or namespace node is the element
7802 * to which the attribute or namespace node is attached
7803 * Namespace handling !!!
7804 */
7805 if (cur == NULL) {
7806 if (ctxt->context->node == NULL) return(NULL);
7807 switch (ctxt->context->node->type) {
7808 case XML_ELEMENT_NODE:
7809 case XML_TEXT_NODE:
7810 case XML_CDATA_SECTION_NODE:
7811 case XML_ENTITY_REF_NODE:
7812 case XML_ENTITY_NODE:
7813 case XML_PI_NODE:
7814 case XML_COMMENT_NODE:
7815 case XML_NOTATION_NODE:
7816 case XML_DTD_NODE:
7817 case XML_ELEMENT_DECL:
7818 case XML_ATTRIBUTE_DECL:
7819 case XML_XINCLUDE_START:
7820 case XML_XINCLUDE_END:
7821 case XML_ENTITY_DECL:
7822 if (ctxt->context->node->parent == NULL)
7823 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007824 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007825 ((ctxt->context->node->parent->name[0] == ' ') ||
7826 (xmlStrEqual(ctxt->context->node->parent->name,
7827 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007828 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007829 return(ctxt->context->node->parent);
7830 case XML_ATTRIBUTE_NODE: {
7831 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7832
7833 return(att->parent);
7834 }
7835 case XML_DOCUMENT_NODE:
7836 case XML_DOCUMENT_TYPE_NODE:
7837 case XML_DOCUMENT_FRAG_NODE:
7838 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007839#ifdef LIBXML_DOCB_ENABLED
7840 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007841#endif
7842 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007843 case XML_NAMESPACE_DECL: {
7844 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7845
7846 if ((ns->next != NULL) &&
7847 (ns->next->type != XML_NAMESPACE_DECL))
7848 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00007849 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007850 }
Owen Taylor3473f882001-02-23 17:55:21 +00007851 }
7852 }
7853 return(NULL);
7854}
7855
7856/**
7857 * xmlXPathNextAncestor:
7858 * @ctxt: the XPath Parser context
7859 * @cur: the current node in the traversal
7860 *
7861 * Traversal function for the "ancestor" direction
7862 * the ancestor axis contains the ancestors of the context node; the ancestors
7863 * of the context node consist of the parent of context node and the parent's
7864 * parent and so on; the nodes are ordered in reverse document order; thus the
7865 * parent is the first node on the axis, and the parent's parent is the second
7866 * node on the axis
7867 *
7868 * Returns the next element following that axis
7869 */
7870xmlNodePtr
7871xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007872 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007873 /*
7874 * the parent of an attribute or namespace node is the element
7875 * to which the attribute or namespace node is attached
7876 * !!!!!!!!!!!!!
7877 */
7878 if (cur == NULL) {
7879 if (ctxt->context->node == NULL) return(NULL);
7880 switch (ctxt->context->node->type) {
7881 case XML_ELEMENT_NODE:
7882 case XML_TEXT_NODE:
7883 case XML_CDATA_SECTION_NODE:
7884 case XML_ENTITY_REF_NODE:
7885 case XML_ENTITY_NODE:
7886 case XML_PI_NODE:
7887 case XML_COMMENT_NODE:
7888 case XML_DTD_NODE:
7889 case XML_ELEMENT_DECL:
7890 case XML_ATTRIBUTE_DECL:
7891 case XML_ENTITY_DECL:
7892 case XML_NOTATION_NODE:
7893 case XML_XINCLUDE_START:
7894 case XML_XINCLUDE_END:
7895 if (ctxt->context->node->parent == NULL)
7896 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007897 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007898 ((ctxt->context->node->parent->name[0] == ' ') ||
7899 (xmlStrEqual(ctxt->context->node->parent->name,
7900 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007901 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007902 return(ctxt->context->node->parent);
7903 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007904 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00007905
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007906 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00007907 }
7908 case XML_DOCUMENT_NODE:
7909 case XML_DOCUMENT_TYPE_NODE:
7910 case XML_DOCUMENT_FRAG_NODE:
7911 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007912#ifdef LIBXML_DOCB_ENABLED
7913 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007914#endif
7915 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007916 case XML_NAMESPACE_DECL: {
7917 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7918
7919 if ((ns->next != NULL) &&
7920 (ns->next->type != XML_NAMESPACE_DECL))
7921 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00007922 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00007923 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007924 }
Owen Taylor3473f882001-02-23 17:55:21 +00007925 }
7926 return(NULL);
7927 }
7928 if (cur == ctxt->context->doc->children)
7929 return((xmlNodePtr) ctxt->context->doc);
7930 if (cur == (xmlNodePtr) ctxt->context->doc)
7931 return(NULL);
7932 switch (cur->type) {
7933 case XML_ELEMENT_NODE:
7934 case XML_TEXT_NODE:
7935 case XML_CDATA_SECTION_NODE:
7936 case XML_ENTITY_REF_NODE:
7937 case XML_ENTITY_NODE:
7938 case XML_PI_NODE:
7939 case XML_COMMENT_NODE:
7940 case XML_NOTATION_NODE:
7941 case XML_DTD_NODE:
7942 case XML_ELEMENT_DECL:
7943 case XML_ATTRIBUTE_DECL:
7944 case XML_ENTITY_DECL:
7945 case XML_XINCLUDE_START:
7946 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007947 if (cur->parent == NULL)
7948 return(NULL);
7949 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007950 ((cur->parent->name[0] == ' ') ||
7951 (xmlStrEqual(cur->parent->name,
7952 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007953 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007954 return(cur->parent);
7955 case XML_ATTRIBUTE_NODE: {
7956 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7957
7958 return(att->parent);
7959 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00007960 case XML_NAMESPACE_DECL: {
7961 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7962
7963 if ((ns->next != NULL) &&
7964 (ns->next->type != XML_NAMESPACE_DECL))
7965 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00007966 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00007967 return(NULL);
7968 }
Owen Taylor3473f882001-02-23 17:55:21 +00007969 case XML_DOCUMENT_NODE:
7970 case XML_DOCUMENT_TYPE_NODE:
7971 case XML_DOCUMENT_FRAG_NODE:
7972 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007973#ifdef LIBXML_DOCB_ENABLED
7974 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007975#endif
7976 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007977 }
7978 return(NULL);
7979}
7980
7981/**
7982 * xmlXPathNextAncestorOrSelf:
7983 * @ctxt: the XPath Parser context
7984 * @cur: the current node in the traversal
7985 *
7986 * Traversal function for the "ancestor-or-self" direction
7987 * he ancestor-or-self axis contains the context node and ancestors of
7988 * the context node in reverse document order; thus the context node is
7989 * the first node on the axis, and the context node's parent the second;
7990 * parent here is defined the same as with the parent axis.
7991 *
7992 * Returns the next element following that axis
7993 */
7994xmlNodePtr
7995xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007996 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007997 if (cur == NULL)
7998 return(ctxt->context->node);
7999 return(xmlXPathNextAncestor(ctxt, cur));
8000}
8001
8002/**
8003 * xmlXPathNextFollowingSibling:
8004 * @ctxt: the XPath Parser context
8005 * @cur: the current node in the traversal
8006 *
8007 * Traversal function for the "following-sibling" direction
8008 * The following-sibling axis contains the following siblings of the context
8009 * node in document order.
8010 *
8011 * Returns the next element following that axis
8012 */
8013xmlNodePtr
8014xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008015 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008016 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8017 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8018 return(NULL);
8019 if (cur == (xmlNodePtr) ctxt->context->doc)
8020 return(NULL);
8021 if (cur == NULL)
8022 return(ctxt->context->node->next);
8023 return(cur->next);
8024}
8025
8026/**
8027 * xmlXPathNextPrecedingSibling:
8028 * @ctxt: the XPath Parser context
8029 * @cur: the current node in the traversal
8030 *
8031 * Traversal function for the "preceding-sibling" direction
8032 * The preceding-sibling axis contains the preceding siblings of the context
8033 * node in reverse document order; the first preceding sibling is first on the
8034 * axis; the sibling preceding that node is the second on the axis and so on.
8035 *
8036 * Returns the next element following that axis
8037 */
8038xmlNodePtr
8039xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008040 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008041 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8042 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8043 return(NULL);
8044 if (cur == (xmlNodePtr) ctxt->context->doc)
8045 return(NULL);
8046 if (cur == NULL)
8047 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008048 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8049 cur = cur->prev;
8050 if (cur == NULL)
8051 return(ctxt->context->node->prev);
8052 }
Owen Taylor3473f882001-02-23 17:55:21 +00008053 return(cur->prev);
8054}
8055
8056/**
8057 * xmlXPathNextFollowing:
8058 * @ctxt: the XPath Parser context
8059 * @cur: the current node in the traversal
8060 *
8061 * Traversal function for the "following" direction
8062 * The following axis contains all nodes in the same document as the context
8063 * node that are after the context node in document order, excluding any
8064 * descendants and excluding attribute nodes and namespace nodes; the nodes
8065 * are ordered in document order
8066 *
8067 * Returns the next element following that axis
8068 */
8069xmlNodePtr
8070xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008071 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008072 if (cur != NULL && cur->children != NULL)
8073 return cur->children ;
8074 if (cur == NULL) cur = ctxt->context->node;
8075 if (cur == NULL) return(NULL) ; /* ERROR */
8076 if (cur->next != NULL) return(cur->next) ;
8077 do {
8078 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00008079 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00008080 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8081 if (cur->next != NULL) return(cur->next);
8082 } while (cur != NULL);
8083 return(cur);
8084}
8085
8086/*
8087 * xmlXPathIsAncestor:
8088 * @ancestor: the ancestor node
8089 * @node: the current node
8090 *
8091 * Check that @ancestor is a @node's ancestor
8092 *
8093 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8094 */
8095static int
8096xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8097 if ((ancestor == NULL) || (node == NULL)) return(0);
8098 /* nodes need to be in the same document */
8099 if (ancestor->doc != node->doc) return(0);
8100 /* avoid searching if ancestor or node is the root node */
8101 if (ancestor == (xmlNodePtr) node->doc) return(1);
8102 if (node == (xmlNodePtr) ancestor->doc) return(0);
8103 while (node->parent != NULL) {
8104 if (node->parent == ancestor)
8105 return(1);
8106 node = node->parent;
8107 }
8108 return(0);
8109}
8110
8111/**
8112 * xmlXPathNextPreceding:
8113 * @ctxt: the XPath Parser context
8114 * @cur: the current node in the traversal
8115 *
8116 * Traversal function for the "preceding" direction
8117 * the preceding axis contains all nodes in the same document as the context
8118 * node that are before the context node in document order, excluding any
8119 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8120 * ordered in reverse document order
8121 *
8122 * Returns the next element following that axis
8123 */
8124xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00008125xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8126{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008127 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008128 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008129 cur = ctxt->context->node;
8130 if (cur == NULL)
8131 return (NULL);
8132 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8133 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00008134 do {
8135 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008136 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8137 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008138 }
8139
8140 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008141 if (cur == NULL)
8142 return (NULL);
8143 if (cur == ctxt->context->doc->children)
8144 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008145 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00008146 return (cur);
8147}
8148
8149/**
8150 * xmlXPathNextPrecedingInternal:
8151 * @ctxt: the XPath Parser context
8152 * @cur: the current node in the traversal
8153 *
8154 * Traversal function for the "preceding" direction
8155 * the preceding axis contains all nodes in the same document as the context
8156 * node that are before the context node in document order, excluding any
8157 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8158 * ordered in reverse document order
8159 * This is a faster implementation but internal only since it requires a
8160 * state kept in the parser context: ctxt->ancestor.
8161 *
8162 * Returns the next element following that axis
8163 */
8164static xmlNodePtr
8165xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8166 xmlNodePtr cur)
8167{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008168 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008169 if (cur == NULL) {
8170 cur = ctxt->context->node;
8171 if (cur == NULL)
8172 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00008173 if (cur->type == XML_NAMESPACE_DECL)
8174 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008175 ctxt->ancestor = cur->parent;
8176 }
8177 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8178 cur = cur->prev;
8179 while (cur->prev == NULL) {
8180 cur = cur->parent;
8181 if (cur == NULL)
8182 return (NULL);
8183 if (cur == ctxt->context->doc->children)
8184 return (NULL);
8185 if (cur != ctxt->ancestor)
8186 return (cur);
8187 ctxt->ancestor = cur->parent;
8188 }
8189 cur = cur->prev;
8190 while (cur->last != NULL)
8191 cur = cur->last;
8192 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008193}
8194
8195/**
8196 * xmlXPathNextNamespace:
8197 * @ctxt: the XPath Parser context
8198 * @cur: the current attribute in the traversal
8199 *
8200 * Traversal function for the "namespace" direction
8201 * the namespace axis contains the namespace nodes of the context node;
8202 * the order of nodes on this axis is implementation-defined; the axis will
8203 * be empty unless the context node is an element
8204 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008205 * We keep the XML namespace node at the end of the list.
8206 *
Owen Taylor3473f882001-02-23 17:55:21 +00008207 * Returns the next element following that axis
8208 */
8209xmlNodePtr
8210xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008211 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008212 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00008213 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008214 if (ctxt->context->tmpNsList != NULL)
8215 xmlFree(ctxt->context->tmpNsList);
8216 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00008217 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008218 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00008219 if (ctxt->context->tmpNsList != NULL) {
8220 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8221 ctxt->context->tmpNsNr++;
8222 }
8223 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008224 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008225 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00008226 if (ctxt->context->tmpNsNr > 0) {
8227 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8228 } else {
8229 if (ctxt->context->tmpNsList != NULL)
8230 xmlFree(ctxt->context->tmpNsList);
8231 ctxt->context->tmpNsList = NULL;
8232 return(NULL);
8233 }
Owen Taylor3473f882001-02-23 17:55:21 +00008234}
8235
8236/**
8237 * xmlXPathNextAttribute:
8238 * @ctxt: the XPath Parser context
8239 * @cur: the current attribute in the traversal
8240 *
8241 * Traversal function for the "attribute" direction
8242 * TODO: support DTD inherited default attributes
8243 *
8244 * Returns the next element following that axis
8245 */
8246xmlNodePtr
8247xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008248 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00008249 if (ctxt->context->node == NULL)
8250 return(NULL);
8251 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8252 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008253 if (cur == NULL) {
8254 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8255 return(NULL);
8256 return((xmlNodePtr)ctxt->context->node->properties);
8257 }
8258 return((xmlNodePtr)cur->next);
8259}
8260
8261/************************************************************************
8262 * *
8263 * NodeTest Functions *
8264 * *
8265 ************************************************************************/
8266
Owen Taylor3473f882001-02-23 17:55:21 +00008267#define IS_FUNCTION 200
8268
Owen Taylor3473f882001-02-23 17:55:21 +00008269
8270/************************************************************************
8271 * *
8272 * Implicit tree core function library *
8273 * *
8274 ************************************************************************/
8275
8276/**
8277 * xmlXPathRoot:
8278 * @ctxt: the XPath Parser context
8279 *
8280 * Initialize the context to the root of the document
8281 */
8282void
8283xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008284 if ((ctxt == NULL) || (ctxt->context == NULL))
8285 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008286 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008287 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8288 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008289}
8290
8291/************************************************************************
8292 * *
8293 * The explicit core function library *
8294 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8295 * *
8296 ************************************************************************/
8297
8298
8299/**
8300 * xmlXPathLastFunction:
8301 * @ctxt: the XPath Parser context
8302 * @nargs: the number of arguments
8303 *
8304 * Implement the last() XPath function
8305 * number last()
8306 * The last function returns the number of nodes in the context node list.
8307 */
8308void
8309xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8310 CHECK_ARITY(0);
8311 if (ctxt->context->contextSize >= 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008312 valuePush(ctxt,
8313 xmlXPathCacheNewFloat(ctxt->context,
8314 (double) ctxt->context->contextSize));
Owen Taylor3473f882001-02-23 17:55:21 +00008315#ifdef DEBUG_EXPR
8316 xmlGenericError(xmlGenericErrorContext,
8317 "last() : %d\n", ctxt->context->contextSize);
8318#endif
8319 } else {
8320 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8321 }
8322}
8323
8324/**
8325 * xmlXPathPositionFunction:
8326 * @ctxt: the XPath Parser context
8327 * @nargs: the number of arguments
8328 *
8329 * Implement the position() XPath function
8330 * number position()
8331 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008332 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00008333 * will be equal to last().
8334 */
8335void
8336xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8337 CHECK_ARITY(0);
8338 if (ctxt->context->proximityPosition >= 0) {
8339 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008340 xmlXPathCacheNewFloat(ctxt->context,
8341 (double) ctxt->context->proximityPosition));
Owen Taylor3473f882001-02-23 17:55:21 +00008342#ifdef DEBUG_EXPR
8343 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8344 ctxt->context->proximityPosition);
8345#endif
8346 } else {
8347 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8348 }
8349}
8350
8351/**
8352 * xmlXPathCountFunction:
8353 * @ctxt: the XPath Parser context
8354 * @nargs: the number of arguments
8355 *
8356 * Implement the count() XPath function
8357 * number count(node-set)
8358 */
8359void
8360xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8361 xmlXPathObjectPtr cur;
8362
8363 CHECK_ARITY(1);
8364 if ((ctxt->value == NULL) ||
8365 ((ctxt->value->type != XPATH_NODESET) &&
8366 (ctxt->value->type != XPATH_XSLT_TREE)))
8367 XP_ERROR(XPATH_INVALID_TYPE);
8368 cur = valuePop(ctxt);
8369
Daniel Veillard911f49a2001-04-07 15:39:35 +00008370 if ((cur == NULL) || (cur->nodesetval == NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008371 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00008372 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008373 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8374 (double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00008375 } else {
8376 if ((cur->nodesetval->nodeNr != 1) ||
8377 (cur->nodesetval->nodeTab == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008378 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00008379 } else {
8380 xmlNodePtr tmp;
8381 int i = 0;
8382
8383 tmp = cur->nodesetval->nodeTab[0];
8384 if (tmp != NULL) {
8385 tmp = tmp->children;
8386 while (tmp != NULL) {
8387 tmp = tmp->next;
8388 i++;
8389 }
8390 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008391 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
Daniel Veillardfe703322001-08-14 12:18:09 +00008392 }
8393 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008394 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008395}
8396
8397/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008398 * xmlXPathGetElementsByIds:
8399 * @doc: the document
8400 * @ids: a whitespace separated list of IDs
8401 *
8402 * Selects elements by their unique ID.
8403 *
8404 * Returns a node-set of selected elements.
8405 */
8406static xmlNodeSetPtr
8407xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8408 xmlNodeSetPtr ret;
8409 const xmlChar *cur = ids;
8410 xmlChar *ID;
8411 xmlAttrPtr attr;
8412 xmlNodePtr elem = NULL;
8413
Daniel Veillard7a985a12003-07-06 17:57:42 +00008414 if (ids == NULL) return(NULL);
8415
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008416 ret = xmlXPathNodeSetCreate(NULL);
8417
William M. Brack76e95df2003-10-18 16:20:14 +00008418 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008419 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008420 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00008421 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008422
8423 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00008424 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00008425 /*
8426 * We used to check the fact that the value passed
8427 * was an NCName, but this generated much troubles for
8428 * me and Aleksey Sanin, people blatantly violated that
8429 * constaint, like Visa3D spec.
8430 * if (xmlValidateNCName(ID, 1) == 0)
8431 */
8432 attr = xmlGetID(doc, ID);
8433 if (attr != NULL) {
8434 if (attr->type == XML_ATTRIBUTE_NODE)
8435 elem = attr->parent;
8436 else if (attr->type == XML_ELEMENT_NODE)
8437 elem = (xmlNodePtr) attr;
8438 else
8439 elem = NULL;
8440 if (elem != NULL)
8441 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00008442 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008443 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00008444 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008445
William M. Brack76e95df2003-10-18 16:20:14 +00008446 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008447 ids = cur;
8448 }
8449 return(ret);
8450}
8451
8452/**
Owen Taylor3473f882001-02-23 17:55:21 +00008453 * xmlXPathIdFunction:
8454 * @ctxt: the XPath Parser context
8455 * @nargs: the number of arguments
8456 *
8457 * Implement the id() XPath function
8458 * node-set id(object)
8459 * The id function selects elements by their unique ID
8460 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8461 * then the result is the union of the result of applying id to the
8462 * string value of each of the nodes in the argument node-set. When the
8463 * argument to id is of any other type, the argument is converted to a
8464 * string as if by a call to the string function; the string is split
8465 * into a whitespace-separated list of tokens (whitespace is any sequence
8466 * of characters matching the production S); the result is a node-set
8467 * containing the elements in the same document as the context node that
8468 * have a unique ID equal to any of the tokens in the list.
8469 */
8470void
8471xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008472 xmlChar *tokens;
8473 xmlNodeSetPtr ret;
8474 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00008475
8476 CHECK_ARITY(1);
8477 obj = valuePop(ctxt);
8478 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00008479 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008480 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00008481 int i;
8482
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008483 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008484
Daniel Veillard911f49a2001-04-07 15:39:35 +00008485 if (obj->nodesetval != NULL) {
8486 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008487 tokens =
8488 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8489 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8490 ret = xmlXPathNodeSetMerge(ret, ns);
8491 xmlXPathFreeNodeSet(ns);
8492 if (tokens != NULL)
8493 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00008494 }
Owen Taylor3473f882001-02-23 17:55:21 +00008495 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008496 xmlXPathReleaseObject(ctxt->context, obj);
8497 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00008498 return;
8499 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008500 obj = xmlXPathCacheConvertString(ctxt->context, obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008501 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008502 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8503 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00008504 return;
8505}
8506
8507/**
8508 * xmlXPathLocalNameFunction:
8509 * @ctxt: the XPath Parser context
8510 * @nargs: the number of arguments
8511 *
8512 * Implement the local-name() XPath function
8513 * string local-name(node-set?)
8514 * The local-name function returns a string containing the local part
8515 * of the name of the node in the argument node-set that is first in
8516 * document order. If the node-set is empty or the first node has no
8517 * name, an empty string is returned. If the argument is omitted it
8518 * defaults to the context node.
8519 */
8520void
8521xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8522 xmlXPathObjectPtr cur;
8523
Daniel Veillarda82b1822004-11-08 16:24:57 +00008524 if (ctxt == NULL) return;
8525
Owen Taylor3473f882001-02-23 17:55:21 +00008526 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008527 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8528 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008529 nargs = 1;
8530 }
8531
8532 CHECK_ARITY(1);
8533 if ((ctxt->value == NULL) ||
8534 ((ctxt->value->type != XPATH_NODESET) &&
8535 (ctxt->value->type != XPATH_XSLT_TREE)))
8536 XP_ERROR(XPATH_INVALID_TYPE);
8537 cur = valuePop(ctxt);
8538
Daniel Veillard911f49a2001-04-07 15:39:35 +00008539 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008540 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008541 } else {
8542 int i = 0; /* Should be first in document order !!!!! */
8543 switch (cur->nodesetval->nodeTab[i]->type) {
8544 case XML_ELEMENT_NODE:
8545 case XML_ATTRIBUTE_NODE:
8546 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008547 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008548 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008549 else
8550 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008551 xmlXPathCacheNewString(ctxt->context,
8552 cur->nodesetval->nodeTab[i]->name));
Owen Taylor3473f882001-02-23 17:55:21 +00008553 break;
8554 case XML_NAMESPACE_DECL:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008555 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008556 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8557 break;
8558 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008559 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008560 }
8561 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008562 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008563}
8564
8565/**
8566 * xmlXPathNamespaceURIFunction:
8567 * @ctxt: the XPath Parser context
8568 * @nargs: the number of arguments
8569 *
8570 * Implement the namespace-uri() XPath function
8571 * string namespace-uri(node-set?)
8572 * The namespace-uri function returns a string containing the
8573 * namespace URI of the expanded name of the node in the argument
8574 * node-set that is first in document order. If the node-set is empty,
8575 * the first node has no name, or the expanded name has no namespace
8576 * URI, an empty string is returned. If the argument is omitted it
8577 * defaults to the context node.
8578 */
8579void
8580xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8581 xmlXPathObjectPtr cur;
8582
Daniel Veillarda82b1822004-11-08 16:24:57 +00008583 if (ctxt == NULL) return;
8584
Owen Taylor3473f882001-02-23 17:55:21 +00008585 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008586 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8587 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008588 nargs = 1;
8589 }
8590 CHECK_ARITY(1);
8591 if ((ctxt->value == NULL) ||
8592 ((ctxt->value->type != XPATH_NODESET) &&
8593 (ctxt->value->type != XPATH_XSLT_TREE)))
8594 XP_ERROR(XPATH_INVALID_TYPE);
8595 cur = valuePop(ctxt);
8596
Daniel Veillard911f49a2001-04-07 15:39:35 +00008597 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008598 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008599 } else {
8600 int i = 0; /* Should be first in document order !!!!! */
8601 switch (cur->nodesetval->nodeTab[i]->type) {
8602 case XML_ELEMENT_NODE:
8603 case XML_ATTRIBUTE_NODE:
8604 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008605 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008606 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008607 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008608 cur->nodesetval->nodeTab[i]->ns->href));
8609 break;
8610 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008611 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008612 }
8613 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008614 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008615}
8616
8617/**
8618 * xmlXPathNameFunction:
8619 * @ctxt: the XPath Parser context
8620 * @nargs: the number of arguments
8621 *
8622 * Implement the name() XPath function
8623 * string name(node-set?)
8624 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008625 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00008626 * order. The QName must represent the name with respect to the namespace
8627 * declarations in effect on the node whose name is being represented.
8628 * Typically, this will be the form in which the name occurred in the XML
8629 * source. This need not be the case if there are namespace declarations
8630 * in effect on the node that associate multiple prefixes with the same
8631 * namespace. However, an implementation may include information about
8632 * the original prefix in its representation of nodes; in this case, an
8633 * implementation can ensure that the returned string is always the same
8634 * as the QName used in the XML source. If the argument it omitted it
8635 * defaults to the context node.
8636 * Libxml keep the original prefix so the "real qualified name" used is
8637 * returned.
8638 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008639static void
Daniel Veillard04383752001-07-08 14:27:15 +00008640xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8641{
Owen Taylor3473f882001-02-23 17:55:21 +00008642 xmlXPathObjectPtr cur;
8643
8644 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008645 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8646 ctxt->context->node));
Daniel Veillard04383752001-07-08 14:27:15 +00008647 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008648 }
8649
8650 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00008651 if ((ctxt->value == NULL) ||
8652 ((ctxt->value->type != XPATH_NODESET) &&
8653 (ctxt->value->type != XPATH_XSLT_TREE)))
8654 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00008655 cur = valuePop(ctxt);
8656
Daniel Veillard911f49a2001-04-07 15:39:35 +00008657 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008658 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008659 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00008660 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00008661
Daniel Veillard04383752001-07-08 14:27:15 +00008662 switch (cur->nodesetval->nodeTab[i]->type) {
8663 case XML_ELEMENT_NODE:
8664 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008665 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008666 valuePush(ctxt,
8667 xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008668 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8669 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008670 valuePush(ctxt,
8671 xmlXPathCacheNewString(ctxt->context,
8672 cur->nodesetval->nodeTab[i]->name));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008673 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00008674 xmlChar *fullname;
8675
8676 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8677 cur->nodesetval->nodeTab[i]->ns->prefix,
8678 NULL, 0);
8679 if (fullname == cur->nodesetval->nodeTab[i]->name)
8680 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8681 if (fullname == NULL) {
8682 XP_ERROR(XPATH_MEMORY_ERROR);
8683 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008684 valuePush(ctxt, xmlXPathCacheWrapString(
8685 ctxt->context, fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00008686 }
8687 break;
8688 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008689 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8690 cur->nodesetval->nodeTab[i]));
Daniel Veillard04383752001-07-08 14:27:15 +00008691 xmlXPathLocalNameFunction(ctxt, 1);
8692 }
Owen Taylor3473f882001-02-23 17:55:21 +00008693 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008694 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008695}
8696
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008697
8698/**
Owen Taylor3473f882001-02-23 17:55:21 +00008699 * xmlXPathStringFunction:
8700 * @ctxt: the XPath Parser context
8701 * @nargs: the number of arguments
8702 *
8703 * Implement the string() XPath function
8704 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00008705 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00008706 * - A node-set is converted to a string by returning the value of
8707 * the node in the node-set that is first in document order.
8708 * If the node-set is empty, an empty string is returned.
8709 * - A number is converted to a string as follows
8710 * + NaN is converted to the string NaN
8711 * + positive zero is converted to the string 0
8712 * + negative zero is converted to the string 0
8713 * + positive infinity is converted to the string Infinity
8714 * + negative infinity is converted to the string -Infinity
8715 * + if the number is an integer, the number is represented in
8716 * decimal form as a Number with no decimal point and no leading
8717 * zeros, preceded by a minus sign (-) if the number is negative
8718 * + otherwise, the number is represented in decimal form as a
8719 * Number including a decimal point with at least one digit
8720 * before the decimal point and at least one digit after the
8721 * decimal point, preceded by a minus sign (-) if the number
8722 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008723 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00008724 * before the decimal point; beyond the one required digit
8725 * after the decimal point there must be as many, but only as
8726 * many, more digits as are needed to uniquely distinguish the
8727 * number from all other IEEE 754 numeric values.
8728 * - The boolean false value is converted to the string false.
8729 * The boolean true value is converted to the string true.
8730 *
8731 * If the argument is omitted, it defaults to a node-set with the
8732 * context node as its only member.
8733 */
8734void
8735xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8736 xmlXPathObjectPtr cur;
8737
Daniel Veillarda82b1822004-11-08 16:24:57 +00008738 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008739 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008740 valuePush(ctxt,
8741 xmlXPathCacheWrapString(ctxt->context,
8742 xmlXPathCastNodeToString(ctxt->context->node)));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008743 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008744 }
8745
8746 CHECK_ARITY(1);
8747 cur = valuePop(ctxt);
8748 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008749 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00008750}
8751
8752/**
8753 * xmlXPathStringLengthFunction:
8754 * @ctxt: the XPath Parser context
8755 * @nargs: the number of arguments
8756 *
8757 * Implement the string-length() XPath function
8758 * number string-length(string?)
8759 * The string-length returns the number of characters in the string
8760 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8761 * the context node converted to a string, in other words the value
8762 * of the context node.
8763 */
8764void
8765xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8766 xmlXPathObjectPtr cur;
8767
8768 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008769 if ((ctxt == NULL) || (ctxt->context == NULL))
8770 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008771 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008772 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008773 } else {
8774 xmlChar *content;
8775
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008776 content = xmlXPathCastNodeToString(ctxt->context->node);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008777 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8778 xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00008779 xmlFree(content);
8780 }
8781 return;
8782 }
8783 CHECK_ARITY(1);
8784 CAST_TO_STRING;
8785 CHECK_TYPE(XPATH_STRING);
8786 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008787 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8788 xmlUTF8Strlen(cur->stringval)));
8789 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008790}
8791
8792/**
8793 * xmlXPathConcatFunction:
8794 * @ctxt: the XPath Parser context
8795 * @nargs: the number of arguments
8796 *
8797 * Implement the concat() XPath function
8798 * string concat(string, string, string*)
8799 * The concat function returns the concatenation of its arguments.
8800 */
8801void
8802xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8803 xmlXPathObjectPtr cur, newobj;
8804 xmlChar *tmp;
8805
Daniel Veillarda82b1822004-11-08 16:24:57 +00008806 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008807 if (nargs < 2) {
8808 CHECK_ARITY(2);
8809 }
8810
8811 CAST_TO_STRING;
8812 cur = valuePop(ctxt);
8813 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008814 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008815 return;
8816 }
8817 nargs--;
8818
8819 while (nargs > 0) {
8820 CAST_TO_STRING;
8821 newobj = valuePop(ctxt);
8822 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008823 xmlXPathReleaseObject(ctxt->context, newobj);
8824 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008825 XP_ERROR(XPATH_INVALID_TYPE);
8826 }
8827 tmp = xmlStrcat(newobj->stringval, cur->stringval);
8828 newobj->stringval = cur->stringval;
8829 cur->stringval = tmp;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008830 xmlXPathReleaseObject(ctxt->context, newobj);
Owen Taylor3473f882001-02-23 17:55:21 +00008831 nargs--;
8832 }
8833 valuePush(ctxt, cur);
8834}
8835
8836/**
8837 * xmlXPathContainsFunction:
8838 * @ctxt: the XPath Parser context
8839 * @nargs: the number of arguments
8840 *
8841 * Implement the contains() XPath function
8842 * boolean contains(string, string)
8843 * The contains function returns true if the first argument string
8844 * contains the second argument string, and otherwise returns false.
8845 */
8846void
8847xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8848 xmlXPathObjectPtr hay, needle;
8849
8850 CHECK_ARITY(2);
8851 CAST_TO_STRING;
8852 CHECK_TYPE(XPATH_STRING);
8853 needle = valuePop(ctxt);
8854 CAST_TO_STRING;
8855 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008856
Owen Taylor3473f882001-02-23 17:55:21 +00008857 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008858 xmlXPathReleaseObject(ctxt->context, hay);
8859 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008860 XP_ERROR(XPATH_INVALID_TYPE);
8861 }
8862 if (xmlStrstr(hay->stringval, needle->stringval))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008863 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00008864 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008865 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8866 xmlXPathReleaseObject(ctxt->context, hay);
8867 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008868}
8869
8870/**
8871 * xmlXPathStartsWithFunction:
8872 * @ctxt: the XPath Parser context
8873 * @nargs: the number of arguments
8874 *
8875 * Implement the starts-with() XPath function
8876 * boolean starts-with(string, string)
8877 * The starts-with function returns true if the first argument string
8878 * starts with the second argument string, and otherwise returns false.
8879 */
8880void
8881xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8882 xmlXPathObjectPtr hay, needle;
8883 int n;
8884
8885 CHECK_ARITY(2);
8886 CAST_TO_STRING;
8887 CHECK_TYPE(XPATH_STRING);
8888 needle = valuePop(ctxt);
8889 CAST_TO_STRING;
8890 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008891
Owen Taylor3473f882001-02-23 17:55:21 +00008892 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008893 xmlXPathReleaseObject(ctxt->context, hay);
8894 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008895 XP_ERROR(XPATH_INVALID_TYPE);
8896 }
8897 n = xmlStrlen(needle->stringval);
8898 if (xmlStrncmp(hay->stringval, needle->stringval, n))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008899 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008900 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008901 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8902 xmlXPathReleaseObject(ctxt->context, hay);
8903 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008904}
8905
8906/**
8907 * xmlXPathSubstringFunction:
8908 * @ctxt: the XPath Parser context
8909 * @nargs: the number of arguments
8910 *
8911 * Implement the substring() XPath function
8912 * string substring(string, number, number?)
8913 * The substring function returns the substring of the first argument
8914 * starting at the position specified in the second argument with
8915 * length specified in the third argument. For example,
8916 * substring("12345",2,3) returns "234". If the third argument is not
8917 * specified, it returns the substring starting at the position specified
8918 * in the second argument and continuing to the end of the string. For
8919 * example, substring("12345",2) returns "2345". More precisely, each
8920 * character in the string (see [3.6 Strings]) is considered to have a
8921 * numeric position: the position of the first character is 1, the position
8922 * of the second character is 2 and so on. The returned substring contains
8923 * those characters for which the position of the character is greater than
8924 * or equal to the second argument and, if the third argument is specified,
8925 * less than the sum of the second and third arguments; the comparisons
8926 * and addition used for the above follow the standard IEEE 754 rules. Thus:
8927 * - substring("12345", 1.5, 2.6) returns "234"
8928 * - substring("12345", 0, 3) returns "12"
8929 * - substring("12345", 0 div 0, 3) returns ""
8930 * - substring("12345", 1, 0 div 0) returns ""
8931 * - substring("12345", -42, 1 div 0) returns "12345"
8932 * - substring("12345", -1 div 0, 1 div 0) returns ""
8933 */
8934void
8935xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8936 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00008937 double le=0, in;
8938 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00008939 xmlChar *ret;
8940
Owen Taylor3473f882001-02-23 17:55:21 +00008941 if (nargs < 2) {
8942 CHECK_ARITY(2);
8943 }
8944 if (nargs > 3) {
8945 CHECK_ARITY(3);
8946 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008947 /*
8948 * take care of possible last (position) argument
8949 */
Owen Taylor3473f882001-02-23 17:55:21 +00008950 if (nargs == 3) {
8951 CAST_TO_NUMBER;
8952 CHECK_TYPE(XPATH_NUMBER);
8953 len = valuePop(ctxt);
8954 le = len->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008955 xmlXPathReleaseObject(ctxt->context, len);
Owen Taylor3473f882001-02-23 17:55:21 +00008956 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008957
Owen Taylor3473f882001-02-23 17:55:21 +00008958 CAST_TO_NUMBER;
8959 CHECK_TYPE(XPATH_NUMBER);
8960 start = valuePop(ctxt);
8961 in = start->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008962 xmlXPathReleaseObject(ctxt->context, start);
Owen Taylor3473f882001-02-23 17:55:21 +00008963 CAST_TO_STRING;
8964 CHECK_TYPE(XPATH_STRING);
8965 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00008966 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00008967
Daniel Veillard97ac1312001-05-30 19:14:17 +00008968 /*
8969 * If last pos not present, calculate last position
8970 */
Daniel Veillard9e412302002-06-10 15:59:44 +00008971 if (nargs != 3) {
8972 le = (double)m;
8973 if (in < 1.0)
8974 in = 1.0;
8975 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008976
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008977 /* Need to check for the special cases where either
8978 * the index is NaN, the length is NaN, or both
8979 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00008980 */
Daniel Veillard9e412302002-06-10 15:59:44 +00008981 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008982 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00008983 * To meet the requirements of the spec, the arguments
8984 * must be converted to integer format before
8985 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008986 *
Daniel Veillard9e412302002-06-10 15:59:44 +00008987 * First we go to integer form, rounding up
8988 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008989 */
8990 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00008991 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00008992
Daniel Veillard9e412302002-06-10 15:59:44 +00008993 if (xmlXPathIsInf(le) == 1) {
8994 l = m;
8995 if (i < 1)
8996 i = 1;
8997 }
8998 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
8999 l = 0;
9000 else {
9001 l = (int) le;
9002 if (((double)l)+0.5 <= le) l++;
9003 }
9004
9005 /* Now we normalize inidices */
9006 i -= 1;
9007 l += i;
9008 if (i < 0)
9009 i = 0;
9010 if (l > m)
9011 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00009012
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009013 /* number of chars to copy */
9014 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00009015
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009016 ret = xmlUTF8Strsub(str->stringval, i, l);
9017 }
9018 else {
9019 ret = NULL;
9020 }
Owen Taylor3473f882001-02-23 17:55:21 +00009021 if (ret == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009022 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00009023 else {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009024 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009025 xmlFree(ret);
9026 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009027 xmlXPathReleaseObject(ctxt->context, str);
Owen Taylor3473f882001-02-23 17:55:21 +00009028}
9029
9030/**
9031 * xmlXPathSubstringBeforeFunction:
9032 * @ctxt: the XPath Parser context
9033 * @nargs: the number of arguments
9034 *
9035 * Implement the substring-before() XPath function
9036 * string substring-before(string, string)
9037 * The substring-before function returns the substring of the first
9038 * argument string that precedes the first occurrence of the second
9039 * argument string in the first argument string, or the empty string
9040 * if the first argument string does not contain the second argument
9041 * string. For example, substring-before("1999/04/01","/") returns 1999.
9042 */
9043void
9044xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9045 xmlXPathObjectPtr str;
9046 xmlXPathObjectPtr find;
9047 xmlBufferPtr target;
9048 const xmlChar *point;
9049 int offset;
9050
9051 CHECK_ARITY(2);
9052 CAST_TO_STRING;
9053 find = valuePop(ctxt);
9054 CAST_TO_STRING;
9055 str = valuePop(ctxt);
9056
9057 target = xmlBufferCreate();
9058 if (target) {
9059 point = xmlStrstr(str->stringval, find->stringval);
9060 if (point) {
9061 offset = (int)(point - str->stringval);
9062 xmlBufferAdd(target, str->stringval, offset);
9063 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009064 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9065 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00009066 xmlBufferFree(target);
9067 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009068 xmlXPathReleaseObject(ctxt->context, str);
9069 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009070}
9071
9072/**
9073 * xmlXPathSubstringAfterFunction:
9074 * @ctxt: the XPath Parser context
9075 * @nargs: the number of arguments
9076 *
9077 * Implement the substring-after() XPath function
9078 * string substring-after(string, string)
9079 * The substring-after function returns the substring of the first
9080 * argument string that follows the first occurrence of the second
9081 * argument string in the first argument string, or the empty stringi
9082 * if the first argument string does not contain the second argument
9083 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9084 * and substring-after("1999/04/01","19") returns 99/04/01.
9085 */
9086void
9087xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9088 xmlXPathObjectPtr str;
9089 xmlXPathObjectPtr find;
9090 xmlBufferPtr target;
9091 const xmlChar *point;
9092 int offset;
9093
9094 CHECK_ARITY(2);
9095 CAST_TO_STRING;
9096 find = valuePop(ctxt);
9097 CAST_TO_STRING;
9098 str = valuePop(ctxt);
9099
9100 target = xmlBufferCreate();
9101 if (target) {
9102 point = xmlStrstr(str->stringval, find->stringval);
9103 if (point) {
9104 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9105 xmlBufferAdd(target, &str->stringval[offset],
9106 xmlStrlen(str->stringval) - offset);
9107 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009108 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9109 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00009110 xmlBufferFree(target);
9111 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009112 xmlXPathReleaseObject(ctxt->context, str);
9113 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009114}
9115
9116/**
9117 * xmlXPathNormalizeFunction:
9118 * @ctxt: the XPath Parser context
9119 * @nargs: the number of arguments
9120 *
9121 * Implement the normalize-space() XPath function
9122 * string normalize-space(string?)
9123 * The normalize-space function returns the argument string with white
9124 * space normalized by stripping leading and trailing whitespace
9125 * and replacing sequences of whitespace characters by a single
9126 * space. Whitespace characters are the same allowed by the S production
9127 * in XML. If the argument is omitted, it defaults to the context
9128 * node converted to a string, in other words the value of the context node.
9129 */
9130void
9131xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9132 xmlXPathObjectPtr obj = NULL;
9133 xmlChar *source = NULL;
9134 xmlBufferPtr target;
9135 xmlChar blank;
9136
Daniel Veillarda82b1822004-11-08 16:24:57 +00009137 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009138 if (nargs == 0) {
9139 /* Use current context node */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009140 valuePush(ctxt,
9141 xmlXPathCacheWrapString(ctxt->context,
9142 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00009143 nargs = 1;
9144 }
9145
9146 CHECK_ARITY(1);
9147 CAST_TO_STRING;
9148 CHECK_TYPE(XPATH_STRING);
9149 obj = valuePop(ctxt);
9150 source = obj->stringval;
9151
9152 target = xmlBufferCreate();
9153 if (target && source) {
9154
9155 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00009156 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00009157 source++;
9158
9159 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9160 blank = 0;
9161 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00009162 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009163 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00009164 } else {
9165 if (blank) {
9166 xmlBufferAdd(target, &blank, 1);
9167 blank = 0;
9168 }
9169 xmlBufferAdd(target, source, 1);
9170 }
9171 source++;
9172 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009173 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9174 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00009175 xmlBufferFree(target);
9176 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009177 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00009178}
9179
9180/**
9181 * xmlXPathTranslateFunction:
9182 * @ctxt: the XPath Parser context
9183 * @nargs: the number of arguments
9184 *
9185 * Implement the translate() XPath function
9186 * string translate(string, string, string)
9187 * The translate function returns the first argument string with
9188 * occurrences of characters in the second argument string replaced
9189 * by the character at the corresponding position in the third argument
9190 * string. For example, translate("bar","abc","ABC") returns the string
9191 * BAr. If there is a character in the second argument string with no
9192 * character at a corresponding position in the third argument string
9193 * (because the second argument string is longer than the third argument
9194 * string), then occurrences of that character in the first argument
9195 * string are removed. For example, translate("--aaa--","abc-","ABC")
9196 * returns "AAA". If a character occurs more than once in second
9197 * argument string, then the first occurrence determines the replacement
9198 * character. If the third argument string is longer than the second
9199 * argument string, then excess characters are ignored.
9200 */
9201void
9202xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00009203 xmlXPathObjectPtr str;
9204 xmlXPathObjectPtr from;
9205 xmlXPathObjectPtr to;
9206 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009207 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009208 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00009209 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009210 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00009211
Daniel Veillarde043ee12001-04-16 14:08:07 +00009212 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00009213
Daniel Veillarde043ee12001-04-16 14:08:07 +00009214 CAST_TO_STRING;
9215 to = valuePop(ctxt);
9216 CAST_TO_STRING;
9217 from = valuePop(ctxt);
9218 CAST_TO_STRING;
9219 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009220
Daniel Veillarde043ee12001-04-16 14:08:07 +00009221 target = xmlBufferCreate();
9222 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009223 max = xmlUTF8Strlen(to->stringval);
9224 for (cptr = str->stringval; (ch=*cptr); ) {
9225 offset = xmlUTF8Strloc(from->stringval, cptr);
9226 if (offset >= 0) {
9227 if (offset < max) {
9228 point = xmlUTF8Strpos(to->stringval, offset);
9229 if (point)
9230 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
9231 }
9232 } else
9233 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9234
9235 /* Step to next character in input */
9236 cptr++;
9237 if ( ch & 0x80 ) {
9238 /* if not simple ascii, verify proper format */
9239 if ( (ch & 0xc0) != 0xc0 ) {
9240 xmlGenericError(xmlGenericErrorContext,
9241 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9242 break;
9243 }
9244 /* then skip over remaining bytes for this char */
9245 while ( (ch <<= 1) & 0x80 )
9246 if ( (*cptr++ & 0xc0) != 0x80 ) {
9247 xmlGenericError(xmlGenericErrorContext,
9248 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9249 break;
9250 }
9251 if (ch & 0x80) /* must have had error encountered */
9252 break;
9253 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00009254 }
Owen Taylor3473f882001-02-23 17:55:21 +00009255 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009256 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9257 xmlBufferContent(target)));
Daniel Veillarde043ee12001-04-16 14:08:07 +00009258 xmlBufferFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009259 xmlXPathReleaseObject(ctxt->context, str);
9260 xmlXPathReleaseObject(ctxt->context, from);
9261 xmlXPathReleaseObject(ctxt->context, to);
Owen Taylor3473f882001-02-23 17:55:21 +00009262}
9263
9264/**
9265 * xmlXPathBooleanFunction:
9266 * @ctxt: the XPath Parser context
9267 * @nargs: the number of arguments
9268 *
9269 * Implement the boolean() XPath function
9270 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00009271 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00009272 * - a number is true if and only if it is neither positive or
9273 * negative zero nor NaN
9274 * - a node-set is true if and only if it is non-empty
9275 * - a string is true if and only if its length is non-zero
9276 */
9277void
9278xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9279 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00009280
9281 CHECK_ARITY(1);
9282 cur = valuePop(ctxt);
9283 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009284 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009285 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009286}
9287
9288/**
9289 * xmlXPathNotFunction:
9290 * @ctxt: the XPath Parser context
9291 * @nargs: the number of arguments
9292 *
9293 * Implement the not() XPath function
9294 * boolean not(boolean)
9295 * The not function returns true if its argument is false,
9296 * and false otherwise.
9297 */
9298void
9299xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9300 CHECK_ARITY(1);
9301 CAST_TO_BOOLEAN;
9302 CHECK_TYPE(XPATH_BOOLEAN);
9303 ctxt->value->boolval = ! ctxt->value->boolval;
9304}
9305
9306/**
9307 * xmlXPathTrueFunction:
9308 * @ctxt: the XPath Parser context
9309 * @nargs: the number of arguments
9310 *
9311 * Implement the true() XPath function
9312 * boolean true()
9313 */
9314void
9315xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9316 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009317 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009318}
9319
9320/**
9321 * xmlXPathFalseFunction:
9322 * @ctxt: the XPath Parser context
9323 * @nargs: the number of arguments
9324 *
9325 * Implement the false() XPath function
9326 * boolean false()
9327 */
9328void
9329xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9330 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009331 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009332}
9333
9334/**
9335 * xmlXPathLangFunction:
9336 * @ctxt: the XPath Parser context
9337 * @nargs: the number of arguments
9338 *
9339 * Implement the lang() XPath function
9340 * boolean lang(string)
9341 * The lang function returns true or false depending on whether the
9342 * language of the context node as specified by xml:lang attributes
9343 * is the same as or is a sublanguage of the language specified by
9344 * the argument string. The language of the context node is determined
9345 * by the value of the xml:lang attribute on the context node, or, if
9346 * the context node has no xml:lang attribute, by the value of the
9347 * xml:lang attribute on the nearest ancestor of the context node that
9348 * has an xml:lang attribute. If there is no such attribute, then lang
9349 * returns false. If there is such an attribute, then lang returns
9350 * true if the attribute value is equal to the argument ignoring case,
9351 * or if there is some suffix starting with - such that the attribute
9352 * value is equal to the argument ignoring that suffix of the attribute
9353 * value and ignoring case.
9354 */
9355void
9356xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009357 xmlXPathObjectPtr val = NULL;
9358 const xmlChar *theLang = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009359 const xmlChar *lang;
9360 int ret = 0;
9361 int i;
9362
9363 CHECK_ARITY(1);
9364 CAST_TO_STRING;
9365 CHECK_TYPE(XPATH_STRING);
9366 val = valuePop(ctxt);
9367 lang = val->stringval;
9368 theLang = xmlNodeGetLang(ctxt->context->node);
9369 if ((theLang != NULL) && (lang != NULL)) {
9370 for (i = 0;lang[i] != 0;i++)
9371 if (toupper(lang[i]) != toupper(theLang[i]))
9372 goto not_equal;
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009373 if ((theLang[i] == 0) || (theLang[i] == '-'))
9374 ret = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009375 }
9376not_equal:
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009377 if (theLang != NULL)
9378 xmlFree((void *)theLang);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009379
9380 xmlXPathReleaseObject(ctxt->context, val);
9381 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009382}
9383
9384/**
9385 * xmlXPathNumberFunction:
9386 * @ctxt: the XPath Parser context
9387 * @nargs: the number of arguments
9388 *
9389 * Implement the number() XPath function
9390 * number number(object?)
9391 */
9392void
9393xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9394 xmlXPathObjectPtr cur;
9395 double res;
9396
Daniel Veillarda82b1822004-11-08 16:24:57 +00009397 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009398 if (nargs == 0) {
9399 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009400 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
Owen Taylor3473f882001-02-23 17:55:21 +00009401 } else {
9402 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9403
9404 res = xmlXPathStringEvalNumber(content);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009405 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
Owen Taylor3473f882001-02-23 17:55:21 +00009406 xmlFree(content);
9407 }
9408 return;
9409 }
9410
9411 CHECK_ARITY(1);
9412 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009413 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00009414}
9415
9416/**
9417 * xmlXPathSumFunction:
9418 * @ctxt: the XPath Parser context
9419 * @nargs: the number of arguments
9420 *
9421 * Implement the sum() XPath function
9422 * number sum(node-set)
9423 * The sum function returns the sum of the values of the nodes in
9424 * the argument node-set.
9425 */
9426void
9427xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9428 xmlXPathObjectPtr cur;
9429 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009430 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00009431
9432 CHECK_ARITY(1);
9433 if ((ctxt->value == NULL) ||
9434 ((ctxt->value->type != XPATH_NODESET) &&
9435 (ctxt->value->type != XPATH_XSLT_TREE)))
9436 XP_ERROR(XPATH_INVALID_TYPE);
9437 cur = valuePop(ctxt);
9438
William M. Brack08171912003-12-29 02:52:11 +00009439 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009440 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9441 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00009442 }
9443 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009444 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9445 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009446}
9447
William M. Brack3d426662005-04-19 14:40:28 +00009448/*
9449 * To assure working code on multiple platforms, we want to only depend
9450 * upon the characteristic truncation of converting a floating point value
9451 * to an integer. Unfortunately, because of the different storage sizes
9452 * of our internal floating point value (double) and integer (int), we
9453 * can't directly convert (see bug 301162). This macro is a messy
9454 * 'workaround'
9455 */
9456#define XTRUNC(f, v) \
9457 f = fmod((v), INT_MAX); \
9458 f = (v) - (f) + (double)((int)(f));
9459
Owen Taylor3473f882001-02-23 17:55:21 +00009460/**
9461 * xmlXPathFloorFunction:
9462 * @ctxt: the XPath Parser context
9463 * @nargs: the number of arguments
9464 *
9465 * Implement the floor() XPath function
9466 * number floor(number)
9467 * The floor function returns the largest (closest to positive infinity)
9468 * number that is not greater than the argument and that is an integer.
9469 */
9470void
9471xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009472 double f;
9473
Owen Taylor3473f882001-02-23 17:55:21 +00009474 CHECK_ARITY(1);
9475 CAST_TO_NUMBER;
9476 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009477
William M. Brack3d426662005-04-19 14:40:28 +00009478 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009479 if (f != ctxt->value->floatval) {
9480 if (ctxt->value->floatval > 0)
9481 ctxt->value->floatval = f;
9482 else
9483 ctxt->value->floatval = f - 1;
9484 }
Owen Taylor3473f882001-02-23 17:55:21 +00009485}
9486
9487/**
9488 * xmlXPathCeilingFunction:
9489 * @ctxt: the XPath Parser context
9490 * @nargs: the number of arguments
9491 *
9492 * Implement the ceiling() XPath function
9493 * number ceiling(number)
9494 * The ceiling function returns the smallest (closest to negative infinity)
9495 * number that is not less than the argument and that is an integer.
9496 */
9497void
9498xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9499 double f;
9500
9501 CHECK_ARITY(1);
9502 CAST_TO_NUMBER;
9503 CHECK_TYPE(XPATH_NUMBER);
9504
9505#if 0
9506 ctxt->value->floatval = ceil(ctxt->value->floatval);
9507#else
William M. Brack3d426662005-04-19 14:40:28 +00009508 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009509 if (f != ctxt->value->floatval) {
9510 if (ctxt->value->floatval > 0)
9511 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009512 else {
9513 if (ctxt->value->floatval < 0 && f == 0)
9514 ctxt->value->floatval = xmlXPathNZERO;
9515 else
9516 ctxt->value->floatval = f;
9517 }
9518
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009519 }
Owen Taylor3473f882001-02-23 17:55:21 +00009520#endif
9521}
9522
9523/**
9524 * xmlXPathRoundFunction:
9525 * @ctxt: the XPath Parser context
9526 * @nargs: the number of arguments
9527 *
9528 * Implement the round() XPath function
9529 * number round(number)
9530 * The round function returns the number that is closest to the
9531 * argument and that is an integer. If there are two such numbers,
9532 * then the one that is even is returned.
9533 */
9534void
9535xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9536 double f;
9537
9538 CHECK_ARITY(1);
9539 CAST_TO_NUMBER;
9540 CHECK_TYPE(XPATH_NUMBER);
9541
Daniel Veillardcda96922001-08-21 10:56:31 +00009542 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9543 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9544 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009545 (ctxt->value->floatval == 0.0))
9546 return;
9547
William M. Brack3d426662005-04-19 14:40:28 +00009548 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009549 if (ctxt->value->floatval < 0) {
9550 if (ctxt->value->floatval < f - 0.5)
9551 ctxt->value->floatval = f - 1;
9552 else
9553 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009554 if (ctxt->value->floatval == 0)
9555 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009556 } else {
9557 if (ctxt->value->floatval < f + 0.5)
9558 ctxt->value->floatval = f;
9559 else
9560 ctxt->value->floatval = f + 1;
9561 }
Owen Taylor3473f882001-02-23 17:55:21 +00009562}
9563
9564/************************************************************************
9565 * *
9566 * The Parser *
9567 * *
9568 ************************************************************************/
9569
9570/*
William M. Brack08171912003-12-29 02:52:11 +00009571 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00009572 * implementation.
9573 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009574static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009575static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009576static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009577static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00009578static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9579 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00009580
9581/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00009582 * xmlXPathCurrentChar:
9583 * @ctxt: the XPath parser context
9584 * @cur: pointer to the beginning of the char
9585 * @len: pointer to the length of the char read
9586 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009587 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00009588 * bytes in the input buffer.
9589 *
Daniel Veillard60087f32001-10-10 09:45:09 +00009590 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00009591 */
9592
9593static int
9594xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9595 unsigned char c;
9596 unsigned int val;
9597 const xmlChar *cur;
9598
9599 if (ctxt == NULL)
9600 return(0);
9601 cur = ctxt->cur;
9602
9603 /*
9604 * We are supposed to handle UTF8, check it's valid
9605 * From rfc2044: encoding of the Unicode values on UTF-8:
9606 *
9607 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9608 * 0000 0000-0000 007F 0xxxxxxx
9609 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
9610 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
9611 *
9612 * Check for the 0x110000 limit too
9613 */
9614 c = *cur;
9615 if (c & 0x80) {
9616 if ((cur[1] & 0xc0) != 0x80)
9617 goto encoding_error;
9618 if ((c & 0xe0) == 0xe0) {
9619
9620 if ((cur[2] & 0xc0) != 0x80)
9621 goto encoding_error;
9622 if ((c & 0xf0) == 0xf0) {
9623 if (((c & 0xf8) != 0xf0) ||
9624 ((cur[3] & 0xc0) != 0x80))
9625 goto encoding_error;
9626 /* 4-byte code */
9627 *len = 4;
9628 val = (cur[0] & 0x7) << 18;
9629 val |= (cur[1] & 0x3f) << 12;
9630 val |= (cur[2] & 0x3f) << 6;
9631 val |= cur[3] & 0x3f;
9632 } else {
9633 /* 3-byte code */
9634 *len = 3;
9635 val = (cur[0] & 0xf) << 12;
9636 val |= (cur[1] & 0x3f) << 6;
9637 val |= cur[2] & 0x3f;
9638 }
9639 } else {
9640 /* 2-byte code */
9641 *len = 2;
9642 val = (cur[0] & 0x1f) << 6;
9643 val |= cur[1] & 0x3f;
9644 }
9645 if (!IS_CHAR(val)) {
9646 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9647 }
9648 return(val);
9649 } else {
9650 /* 1-byte code */
9651 *len = 1;
9652 return((int) *cur);
9653 }
9654encoding_error:
9655 /*
William M. Brack08171912003-12-29 02:52:11 +00009656 * If we detect an UTF8 error that probably means that the
9657 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00009658 * declaration header. Report the error and switch the encoding
9659 * to ISO-Latin-1 (if you don't like this policy, just declare the
9660 * encoding !)
9661 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00009662 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00009663 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009664}
9665
9666/**
Owen Taylor3473f882001-02-23 17:55:21 +00009667 * xmlXPathParseNCName:
9668 * @ctxt: the XPath Parser context
9669 *
9670 * parse an XML namespace non qualified name.
9671 *
9672 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9673 *
9674 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9675 * CombiningChar | Extender
9676 *
9677 * Returns the namespace name or NULL
9678 */
9679
9680xmlChar *
9681xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00009682 const xmlChar *in;
9683 xmlChar *ret;
9684 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009685
Daniel Veillarda82b1822004-11-08 16:24:57 +00009686 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00009687 /*
9688 * Accelerator for simple ASCII names
9689 */
9690 in = ctxt->cur;
9691 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9692 ((*in >= 0x41) && (*in <= 0x5A)) ||
9693 (*in == '_')) {
9694 in++;
9695 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9696 ((*in >= 0x41) && (*in <= 0x5A)) ||
9697 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00009698 (*in == '_') || (*in == '.') ||
9699 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00009700 in++;
9701 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9702 (*in == '[') || (*in == ']') || (*in == ':') ||
9703 (*in == '@') || (*in == '*')) {
9704 count = in - ctxt->cur;
9705 if (count == 0)
9706 return(NULL);
9707 ret = xmlStrndup(ctxt->cur, count);
9708 ctxt->cur = in;
9709 return(ret);
9710 }
9711 }
9712 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009713}
9714
Daniel Veillard2156a562001-04-28 12:24:34 +00009715
Owen Taylor3473f882001-02-23 17:55:21 +00009716/**
9717 * xmlXPathParseQName:
9718 * @ctxt: the XPath Parser context
9719 * @prefix: a xmlChar **
9720 *
9721 * parse an XML qualified name
9722 *
9723 * [NS 5] QName ::= (Prefix ':')? LocalPart
9724 *
9725 * [NS 6] Prefix ::= NCName
9726 *
9727 * [NS 7] LocalPart ::= NCName
9728 *
9729 * Returns the function returns the local part, and prefix is updated
9730 * to get the Prefix if any.
9731 */
9732
Daniel Veillard56a4cb82001-03-24 17:00:36 +00009733static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00009734xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9735 xmlChar *ret = NULL;
9736
9737 *prefix = NULL;
9738 ret = xmlXPathParseNCName(ctxt);
9739 if (CUR == ':') {
9740 *prefix = ret;
9741 NEXT;
9742 ret = xmlXPathParseNCName(ctxt);
9743 }
9744 return(ret);
9745}
9746
9747/**
9748 * xmlXPathParseName:
9749 * @ctxt: the XPath Parser context
9750 *
9751 * parse an XML name
9752 *
9753 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9754 * CombiningChar | Extender
9755 *
9756 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9757 *
9758 * Returns the namespace name or NULL
9759 */
9760
9761xmlChar *
9762xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009763 const xmlChar *in;
9764 xmlChar *ret;
9765 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009766
Daniel Veillarda82b1822004-11-08 16:24:57 +00009767 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009768 /*
9769 * Accelerator for simple ASCII names
9770 */
9771 in = ctxt->cur;
9772 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9773 ((*in >= 0x41) && (*in <= 0x5A)) ||
9774 (*in == '_') || (*in == ':')) {
9775 in++;
9776 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9777 ((*in >= 0x41) && (*in <= 0x5A)) ||
9778 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00009779 (*in == '_') || (*in == '-') ||
9780 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00009781 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00009782 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009783 count = in - ctxt->cur;
9784 ret = xmlStrndup(ctxt->cur, count);
9785 ctxt->cur = in;
9786 return(ret);
9787 }
9788 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009789 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009790}
9791
Daniel Veillard61d80a22001-04-27 17:13:01 +00009792static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00009793xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009794 xmlChar buf[XML_MAX_NAMELEN + 5];
9795 int len = 0, l;
9796 int c;
9797
9798 /*
9799 * Handler for more complex cases
9800 */
9801 c = CUR_CHAR(l);
9802 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00009803 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9804 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00009805 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00009806 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009807 return(NULL);
9808 }
9809
9810 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9811 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9812 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00009813 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009814 (IS_COMBINING(c)) ||
9815 (IS_EXTENDER(c)))) {
9816 COPY_BUF(l,buf,len,c);
9817 NEXTL(l);
9818 c = CUR_CHAR(l);
9819 if (len >= XML_MAX_NAMELEN) {
9820 /*
9821 * Okay someone managed to make a huge name, so he's ready to pay
9822 * for the processing speed.
9823 */
9824 xmlChar *buffer;
9825 int max = len * 2;
9826
Daniel Veillard3c908dc2003-04-19 00:07:51 +00009827 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009828 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009829 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009830 }
9831 memcpy(buffer, buf, len);
9832 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9833 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00009834 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009835 (IS_COMBINING(c)) ||
9836 (IS_EXTENDER(c))) {
9837 if (len + 10 > max) {
9838 max *= 2;
9839 buffer = (xmlChar *) xmlRealloc(buffer,
9840 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009841 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009842 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009843 }
9844 }
9845 COPY_BUF(l,buffer,len,c);
9846 NEXTL(l);
9847 c = CUR_CHAR(l);
9848 }
9849 buffer[len] = 0;
9850 return(buffer);
9851 }
9852 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009853 if (len == 0)
9854 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009855 return(xmlStrndup(buf, len));
9856}
Daniel Veillard3cd72402002-05-13 10:33:30 +00009857
9858#define MAX_FRAC 20
9859
William M. Brack372a4452004-02-17 13:09:23 +00009860/*
9861 * These are used as divisors for the fractional part of a number.
9862 * Since the table includes 1.0 (representing '0' fractional digits),
9863 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
9864 */
9865static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +00009866 1.0, 10.0, 100.0, 1000.0, 10000.0,
9867 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
9868 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
9869 100000000000000.0,
9870 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +00009871 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +00009872};
9873
Owen Taylor3473f882001-02-23 17:55:21 +00009874/**
9875 * xmlXPathStringEvalNumber:
9876 * @str: A string to scan
9877 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00009878 * [30a] Float ::= Number ('e' Digits?)?
9879 *
Owen Taylor3473f882001-02-23 17:55:21 +00009880 * [30] Number ::= Digits ('.' Digits?)?
9881 * | '.' Digits
9882 * [31] Digits ::= [0-9]+
9883 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009884 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00009885 * In complement of the Number expression, this function also handles
9886 * negative values : '-' Number.
9887 *
9888 * Returns the double value.
9889 */
9890double
9891xmlXPathStringEvalNumber(const xmlChar *str) {
9892 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00009893 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009894 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009895 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009896 int exponent = 0;
9897 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009898#ifdef __GNUC__
9899 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00009900 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009901#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00009902 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00009903 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009904 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
9905 return(xmlXPathNAN);
9906 }
9907 if (*cur == '-') {
9908 isneg = 1;
9909 cur++;
9910 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00009911
9912#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009913 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00009914 * tmp/temp is a workaround against a gcc compiler bug
9915 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009916 */
Daniel Veillard7b416132002-03-07 08:36:03 +00009917 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009918 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00009919 ret = ret * 10;
9920 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00009921 ok = 1;
9922 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00009923 temp = (double) tmp;
9924 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00009925 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00009926#else
Daniel Veillard7b416132002-03-07 08:36:03 +00009927 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009928 while ((*cur >= '0') && (*cur <= '9')) {
9929 ret = ret * 10 + (*cur - '0');
9930 ok = 1;
9931 cur++;
9932 }
9933#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009934
Owen Taylor3473f882001-02-23 17:55:21 +00009935 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00009936 int v, frac = 0;
9937 double fraction = 0;
9938
Owen Taylor3473f882001-02-23 17:55:21 +00009939 cur++;
9940 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
9941 return(xmlXPathNAN);
9942 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00009943 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
9944 v = (*cur - '0');
9945 fraction = fraction * 10 + v;
9946 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009947 cur++;
9948 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00009949 fraction /= my_pow10[frac];
9950 ret = ret + fraction;
9951 while ((*cur >= '0') && (*cur <= '9'))
9952 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009953 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00009954 if ((*cur == 'e') || (*cur == 'E')) {
9955 cur++;
9956 if (*cur == '-') {
9957 is_exponent_negative = 1;
9958 cur++;
William M. Brack99127052004-05-24 02:52:28 +00009959 } else if (*cur == '+') {
9960 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009961 }
9962 while ((*cur >= '0') && (*cur <= '9')) {
9963 exponent = exponent * 10 + (*cur - '0');
9964 cur++;
9965 }
9966 }
William M. Brack76e95df2003-10-18 16:20:14 +00009967 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009968 if (*cur != 0) return(xmlXPathNAN);
9969 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009970 if (is_exponent_negative) exponent = -exponent;
9971 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00009972 return(ret);
9973}
9974
9975/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009976 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00009977 * @ctxt: the XPath Parser context
9978 *
9979 * [30] Number ::= Digits ('.' Digits?)?
9980 * | '.' Digits
9981 * [31] Digits ::= [0-9]+
9982 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009983 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00009984 *
9985 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009986static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009987xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
9988{
Owen Taylor3473f882001-02-23 17:55:21 +00009989 double ret = 0.0;
9990 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00009991 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009992 int exponent = 0;
9993 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00009994#ifdef __GNUC__
9995 unsigned long tmp = 0;
9996 double temp;
9997#endif
Owen Taylor3473f882001-02-23 17:55:21 +00009998
9999 CHECK_ERROR;
10000 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10001 XP_ERROR(XPATH_NUMBER_ERROR);
10002 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010003#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010004 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010005 * tmp/temp is a workaround against a gcc compiler bug
10006 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010007 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010008 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010009 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010010 ret = ret * 10;
10011 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010012 ok = 1;
10013 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +000010014 temp = (double) tmp;
10015 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010016 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010017#else
10018 ret = 0;
10019 while ((CUR >= '0') && (CUR <= '9')) {
10020 ret = ret * 10 + (CUR - '0');
10021 ok = 1;
10022 NEXT;
10023 }
10024#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010025 if (CUR == '.') {
10026 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010027 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10028 XP_ERROR(XPATH_NUMBER_ERROR);
10029 }
10030 while ((CUR >= '0') && (CUR <= '9')) {
10031 mult /= 10;
10032 ret = ret + (CUR - '0') * mult;
10033 NEXT;
10034 }
Owen Taylor3473f882001-02-23 17:55:21 +000010035 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010036 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010037 NEXT;
10038 if (CUR == '-') {
10039 is_exponent_negative = 1;
10040 NEXT;
William M. Brack99127052004-05-24 02:52:28 +000010041 } else if (CUR == '+') {
10042 NEXT;
10043 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010044 while ((CUR >= '0') && (CUR <= '9')) {
10045 exponent = exponent * 10 + (CUR - '0');
10046 NEXT;
10047 }
10048 if (is_exponent_negative)
10049 exponent = -exponent;
10050 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +000010051 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010052 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010053 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010054}
10055
10056/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010057 * xmlXPathParseLiteral:
10058 * @ctxt: the XPath Parser context
10059 *
10060 * Parse a Literal
10061 *
10062 * [29] Literal ::= '"' [^"]* '"'
10063 * | "'" [^']* "'"
10064 *
10065 * Returns the value found or NULL in case of error
10066 */
10067static xmlChar *
10068xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10069 const xmlChar *q;
10070 xmlChar *ret = NULL;
10071
10072 if (CUR == '"') {
10073 NEXT;
10074 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010075 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010076 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010077 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010078 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010079 } else {
10080 ret = xmlStrndup(q, CUR_PTR - q);
10081 NEXT;
10082 }
10083 } else if (CUR == '\'') {
10084 NEXT;
10085 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010086 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010087 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010088 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010089 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010090 } else {
10091 ret = xmlStrndup(q, CUR_PTR - q);
10092 NEXT;
10093 }
10094 } else {
Daniel Veillard24505b02005-07-28 23:49:35 +000010095 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010096 }
10097 return(ret);
10098}
10099
10100/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010101 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +000010102 * @ctxt: the XPath Parser context
10103 *
10104 * Parse a Literal and push it on the stack.
10105 *
10106 * [29] Literal ::= '"' [^"]* '"'
10107 * | "'" [^']* "'"
10108 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010109 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +000010110 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010111static void
10112xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010113 const xmlChar *q;
10114 xmlChar *ret = NULL;
10115
10116 if (CUR == '"') {
10117 NEXT;
10118 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010119 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +000010120 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010121 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010122 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10123 } else {
10124 ret = xmlStrndup(q, CUR_PTR - q);
10125 NEXT;
10126 }
10127 } else if (CUR == '\'') {
10128 NEXT;
10129 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010130 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +000010131 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010132 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010133 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10134 } else {
10135 ret = xmlStrndup(q, CUR_PTR - q);
10136 NEXT;
10137 }
10138 } else {
10139 XP_ERROR(XPATH_START_LITERAL_ERROR);
10140 }
10141 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010142 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010143 xmlXPathCacheNewString(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010144 xmlFree(ret);
10145}
10146
10147/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010148 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +000010149 * @ctxt: the XPath Parser context
10150 *
10151 * Parse a VariableReference, evaluate it and push it on the stack.
10152 *
10153 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +000010154 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +000010155 * of any of the types that are possible for the value of an expression,
10156 * and may also be of additional types not specified here.
10157 *
10158 * Early evaluation is possible since:
10159 * The variable bindings [...] used to evaluate a subexpression are
10160 * always the same as those used to evaluate the containing expression.
10161 *
10162 * [36] VariableReference ::= '$' QName
10163 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010164static void
10165xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010166 xmlChar *name;
10167 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010168
10169 SKIP_BLANKS;
10170 if (CUR != '$') {
10171 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10172 }
10173 NEXT;
10174 name = xmlXPathParseQName(ctxt, &prefix);
10175 if (name == NULL) {
10176 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10177 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010178 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010179 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10180 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010181 SKIP_BLANKS;
Daniel Veillardb3d14912005-09-04 20:47:39 +000010182 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10183 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
10184 }
Owen Taylor3473f882001-02-23 17:55:21 +000010185}
10186
10187/**
10188 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +000010189 * @name: a name string
10190 *
10191 * Is the name given a NodeType one.
10192 *
10193 * [38] NodeType ::= 'comment'
10194 * | 'text'
10195 * | 'processing-instruction'
10196 * | 'node'
10197 *
10198 * Returns 1 if true 0 otherwise
10199 */
10200int
10201xmlXPathIsNodeType(const xmlChar *name) {
10202 if (name == NULL)
10203 return(0);
10204
Daniel Veillard1971ee22002-01-31 20:29:19 +000010205 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +000010206 return(1);
10207 if (xmlStrEqual(name, BAD_CAST "text"))
10208 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010209 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +000010210 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010211 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +000010212 return(1);
10213 return(0);
10214}
10215
10216/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010217 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +000010218 * @ctxt: the XPath Parser context
10219 *
10220 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10221 * [17] Argument ::= Expr
10222 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010223 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +000010224 * pushed on the stack
10225 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010226static void
10227xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010228 xmlChar *name;
10229 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010230 int nbargs = 0;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010231 int sort = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010232
10233 name = xmlXPathParseQName(ctxt, &prefix);
10234 if (name == NULL) {
10235 XP_ERROR(XPATH_EXPR_ERROR);
10236 }
10237 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010238#ifdef DEBUG_EXPR
10239 if (prefix == NULL)
10240 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10241 name);
10242 else
10243 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10244 prefix, name);
10245#endif
10246
Owen Taylor3473f882001-02-23 17:55:21 +000010247 if (CUR != '(') {
10248 XP_ERROR(XPATH_EXPR_ERROR);
10249 }
10250 NEXT;
10251 SKIP_BLANKS;
10252
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010253 /*
10254 * Optimization for count(): we don't need the node-set to be sorted.
10255 */
10256 if ((prefix == NULL) && (name[0] == 'c') &&
10257 xmlStrEqual(name, BAD_CAST "count"))
10258 {
10259 sort = 0;
10260 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010261 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +000010262 if (CUR != ')') {
10263 while (CUR != 0) {
10264 int op1 = ctxt->comp->last;
10265 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010266 xmlXPathCompileExpr(ctxt, sort);
Daniel Veillard71f9d732003-01-14 16:07:16 +000010267 CHECK_ERROR;
10268 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10269 nbargs++;
10270 if (CUR == ')') break;
10271 if (CUR != ',') {
10272 XP_ERROR(XPATH_EXPR_ERROR);
10273 }
10274 NEXT;
10275 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010276 }
Owen Taylor3473f882001-02-23 17:55:21 +000010277 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010278 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10279 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010280 NEXT;
10281 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010282}
10283
10284/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010285 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010286 * @ctxt: the XPath Parser context
10287 *
10288 * [15] PrimaryExpr ::= VariableReference
10289 * | '(' Expr ')'
10290 * | Literal
10291 * | Number
10292 * | FunctionCall
10293 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010294 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010295 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010296static void
10297xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010298 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010299 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010300 else if (CUR == '(') {
10301 NEXT;
10302 SKIP_BLANKS;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010303 xmlXPathCompileExpr(ctxt, 1);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010304 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000010305 if (CUR != ')') {
10306 XP_ERROR(XPATH_EXPR_ERROR);
10307 }
10308 NEXT;
10309 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010310 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010311 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010312 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010313 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010314 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010315 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010316 }
10317 SKIP_BLANKS;
10318}
10319
10320/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010321 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010322 * @ctxt: the XPath Parser context
10323 *
10324 * [20] FilterExpr ::= PrimaryExpr
10325 * | FilterExpr Predicate
10326 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010327 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010328 * Square brackets are used to filter expressions in the same way that
10329 * they are used in location paths. It is an error if the expression to
10330 * be filtered does not evaluate to a node-set. The context node list
10331 * used for evaluating the expression in square brackets is the node-set
10332 * to be filtered listed in document order.
10333 */
10334
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010335static void
10336xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10337 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010338 CHECK_ERROR;
10339 SKIP_BLANKS;
10340
10341 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010342 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +000010343 SKIP_BLANKS;
10344 }
10345
10346
10347}
10348
10349/**
10350 * xmlXPathScanName:
10351 * @ctxt: the XPath Parser context
10352 *
10353 * Trickery: parse an XML name but without consuming the input flow
10354 * Needed to avoid insanity in the parser state.
10355 *
10356 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10357 * CombiningChar | Extender
10358 *
10359 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10360 *
10361 * [6] Names ::= Name (S Name)*
10362 *
10363 * Returns the Name parsed or NULL
10364 */
10365
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010366static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +000010367xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +000010368 int len = 0, l;
10369 int c;
Daniel Veillard03226812004-11-01 14:55:21 +000010370 const xmlChar *cur;
10371 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +000010372
Daniel Veillard03226812004-11-01 14:55:21 +000010373 cur = ctxt->cur;
10374
10375 c = CUR_CHAR(l);
10376 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10377 (!IS_LETTER(c) && (c != '_') &&
10378 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010379 return(NULL);
10380 }
10381
Daniel Veillard03226812004-11-01 14:55:21 +000010382 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10383 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10384 (c == '.') || (c == '-') ||
10385 (c == '_') || (c == ':') ||
10386 (IS_COMBINING(c)) ||
10387 (IS_EXTENDER(c)))) {
10388 len += l;
10389 NEXTL(l);
10390 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +000010391 }
Daniel Veillard03226812004-11-01 14:55:21 +000010392 ret = xmlStrndup(cur, ctxt->cur - cur);
10393 ctxt->cur = cur;
10394 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +000010395}
10396
10397/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010398 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010399 * @ctxt: the XPath Parser context
10400 *
10401 * [19] PathExpr ::= LocationPath
10402 * | FilterExpr
10403 * | FilterExpr '/' RelativeLocationPath
10404 * | FilterExpr '//' RelativeLocationPath
10405 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010406 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010407 * The / operator and // operators combine an arbitrary expression
10408 * and a relative location path. It is an error if the expression
10409 * does not evaluate to a node-set.
10410 * The / operator does composition in the same way as when / is
10411 * used in a location path. As in location paths, // is short for
10412 * /descendant-or-self::node()/.
10413 */
10414
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010415static void
10416xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010417 int lc = 1; /* Should we branch to LocationPath ? */
10418 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10419
10420 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010421 if ((CUR == '$') || (CUR == '(') ||
10422 (IS_ASCII_DIGIT(CUR)) ||
10423 (CUR == '\'') || (CUR == '"') ||
10424 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010425 lc = 0;
10426 } else if (CUR == '*') {
10427 /* relative or absolute location path */
10428 lc = 1;
10429 } else if (CUR == '/') {
10430 /* relative or absolute location path */
10431 lc = 1;
10432 } else if (CUR == '@') {
10433 /* relative abbreviated attribute location path */
10434 lc = 1;
10435 } else if (CUR == '.') {
10436 /* relative abbreviated attribute location path */
10437 lc = 1;
10438 } else {
10439 /*
10440 * Problem is finding if we have a name here whether it's:
10441 * - a nodetype
10442 * - a function call in which case it's followed by '('
10443 * - an axis in which case it's followed by ':'
10444 * - a element name
10445 * We do an a priori analysis here rather than having to
10446 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +000010447 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +000010448 * read/write/debug.
10449 */
10450 SKIP_BLANKS;
10451 name = xmlXPathScanName(ctxt);
10452 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10453#ifdef DEBUG_STEP
10454 xmlGenericError(xmlGenericErrorContext,
10455 "PathExpr: Axis\n");
10456#endif
10457 lc = 1;
10458 xmlFree(name);
10459 } else if (name != NULL) {
10460 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +000010461
10462
10463 while (NXT(len) != 0) {
10464 if (NXT(len) == '/') {
10465 /* element name */
10466#ifdef DEBUG_STEP
10467 xmlGenericError(xmlGenericErrorContext,
10468 "PathExpr: AbbrRelLocation\n");
10469#endif
10470 lc = 1;
10471 break;
William M. Brack76e95df2003-10-18 16:20:14 +000010472 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +000010473 /* ignore blanks */
10474 ;
Owen Taylor3473f882001-02-23 17:55:21 +000010475 } else if (NXT(len) == ':') {
10476#ifdef DEBUG_STEP
10477 xmlGenericError(xmlGenericErrorContext,
10478 "PathExpr: AbbrRelLocation\n");
10479#endif
10480 lc = 1;
10481 break;
10482 } else if ((NXT(len) == '(')) {
10483 /* Note Type or Function */
10484 if (xmlXPathIsNodeType(name)) {
10485#ifdef DEBUG_STEP
10486 xmlGenericError(xmlGenericErrorContext,
10487 "PathExpr: Type search\n");
10488#endif
10489 lc = 1;
10490 } else {
10491#ifdef DEBUG_STEP
10492 xmlGenericError(xmlGenericErrorContext,
10493 "PathExpr: function call\n");
10494#endif
10495 lc = 0;
10496 }
10497 break;
10498 } else if ((NXT(len) == '[')) {
10499 /* element name */
10500#ifdef DEBUG_STEP
10501 xmlGenericError(xmlGenericErrorContext,
10502 "PathExpr: AbbrRelLocation\n");
10503#endif
10504 lc = 1;
10505 break;
10506 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10507 (NXT(len) == '=')) {
10508 lc = 1;
10509 break;
10510 } else {
10511 lc = 1;
10512 break;
10513 }
10514 len++;
10515 }
10516 if (NXT(len) == 0) {
10517#ifdef DEBUG_STEP
10518 xmlGenericError(xmlGenericErrorContext,
10519 "PathExpr: AbbrRelLocation\n");
10520#endif
10521 /* element name */
10522 lc = 1;
10523 }
10524 xmlFree(name);
10525 } else {
William M. Brack08171912003-12-29 02:52:11 +000010526 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +000010527 XP_ERROR(XPATH_EXPR_ERROR);
10528 }
10529 }
10530
10531 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010532 if (CUR == '/') {
10533 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10534 } else {
10535 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010536 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010537 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010538 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010539 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010540 CHECK_ERROR;
10541 if ((CUR == '/') && (NXT(1) == '/')) {
10542 SKIP(2);
10543 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010544
10545 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10546 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10547 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10548
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010549 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010550 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010551 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010552 }
10553 }
10554 SKIP_BLANKS;
10555}
10556
10557/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010558 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010559 * @ctxt: the XPath Parser context
10560 *
10561 * [18] UnionExpr ::= PathExpr
10562 * | UnionExpr '|' PathExpr
10563 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010564 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010565 */
10566
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010567static void
10568xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10569 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010570 CHECK_ERROR;
10571 SKIP_BLANKS;
10572 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010573 int op1 = ctxt->comp->last;
10574 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010575
10576 NEXT;
10577 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010578 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010579
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010580 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10581
Owen Taylor3473f882001-02-23 17:55:21 +000010582 SKIP_BLANKS;
10583 }
Owen Taylor3473f882001-02-23 17:55:21 +000010584}
10585
10586/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010587 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010588 * @ctxt: the XPath Parser context
10589 *
10590 * [27] UnaryExpr ::= UnionExpr
10591 * | '-' UnaryExpr
10592 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010593 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010594 */
10595
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010596static void
10597xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010598 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010599 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010600
10601 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +000010602 while (CUR == '-') {
10603 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010604 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010605 NEXT;
10606 SKIP_BLANKS;
10607 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010608
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010609 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010610 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010611 if (found) {
10612 if (minus)
10613 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10614 else
10615 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010616 }
10617}
10618
10619/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010620 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010621 * @ctxt: the XPath Parser context
10622 *
10623 * [26] MultiplicativeExpr ::= UnaryExpr
10624 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10625 * | MultiplicativeExpr 'div' UnaryExpr
10626 * | MultiplicativeExpr 'mod' UnaryExpr
10627 * [34] MultiplyOperator ::= '*'
10628 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010629 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010630 */
10631
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010632static void
10633xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10634 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010635 CHECK_ERROR;
10636 SKIP_BLANKS;
10637 while ((CUR == '*') ||
10638 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10639 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10640 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010641 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010642
10643 if (CUR == '*') {
10644 op = 0;
10645 NEXT;
10646 } else if (CUR == 'd') {
10647 op = 1;
10648 SKIP(3);
10649 } else if (CUR == 'm') {
10650 op = 2;
10651 SKIP(3);
10652 }
10653 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010654 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010655 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010656 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010657 SKIP_BLANKS;
10658 }
10659}
10660
10661/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010662 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010663 * @ctxt: the XPath Parser context
10664 *
10665 * [25] AdditiveExpr ::= MultiplicativeExpr
10666 * | AdditiveExpr '+' MultiplicativeExpr
10667 * | AdditiveExpr '-' MultiplicativeExpr
10668 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010669 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010670 */
10671
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010672static void
10673xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010674
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010675 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010676 CHECK_ERROR;
10677 SKIP_BLANKS;
10678 while ((CUR == '+') || (CUR == '-')) {
10679 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010680 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010681
10682 if (CUR == '+') plus = 1;
10683 else plus = 0;
10684 NEXT;
10685 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010686 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010687 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010688 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010689 SKIP_BLANKS;
10690 }
10691}
10692
10693/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010694 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010695 * @ctxt: the XPath Parser context
10696 *
10697 * [24] RelationalExpr ::= AdditiveExpr
10698 * | RelationalExpr '<' AdditiveExpr
10699 * | RelationalExpr '>' AdditiveExpr
10700 * | RelationalExpr '<=' AdditiveExpr
10701 * | RelationalExpr '>=' AdditiveExpr
10702 *
10703 * A <= B > C is allowed ? Answer from James, yes with
10704 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10705 * which is basically what got implemented.
10706 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010707 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +000010708 * on the stack
10709 */
10710
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010711static void
10712xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10713 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010714 CHECK_ERROR;
10715 SKIP_BLANKS;
10716 while ((CUR == '<') ||
10717 (CUR == '>') ||
10718 ((CUR == '<') && (NXT(1) == '=')) ||
10719 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010720 int inf, strict;
10721 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010722
10723 if (CUR == '<') inf = 1;
10724 else inf = 0;
10725 if (NXT(1) == '=') strict = 0;
10726 else strict = 1;
10727 NEXT;
10728 if (!strict) NEXT;
10729 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010730 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010731 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010732 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +000010733 SKIP_BLANKS;
10734 }
10735}
10736
10737/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010738 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010739 * @ctxt: the XPath Parser context
10740 *
10741 * [23] EqualityExpr ::= RelationalExpr
10742 * | EqualityExpr '=' RelationalExpr
10743 * | EqualityExpr '!=' RelationalExpr
10744 *
10745 * A != B != C is allowed ? Answer from James, yes with
10746 * (RelationalExpr = RelationalExpr) = RelationalExpr
10747 * (RelationalExpr != RelationalExpr) != RelationalExpr
10748 * which is basically what got implemented.
10749 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010750 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010751 *
10752 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010753static void
10754xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10755 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010756 CHECK_ERROR;
10757 SKIP_BLANKS;
10758 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010759 int eq;
10760 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010761
10762 if (CUR == '=') eq = 1;
10763 else eq = 0;
10764 NEXT;
10765 if (!eq) NEXT;
10766 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010767 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010768 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010769 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010770 SKIP_BLANKS;
10771 }
10772}
10773
10774/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010775 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010776 * @ctxt: the XPath Parser context
10777 *
10778 * [22] AndExpr ::= EqualityExpr
10779 * | AndExpr 'and' EqualityExpr
10780 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010781 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010782 *
10783 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010784static void
10785xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10786 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010787 CHECK_ERROR;
10788 SKIP_BLANKS;
10789 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010790 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010791 SKIP(3);
10792 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010793 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010794 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010795 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010796 SKIP_BLANKS;
10797 }
10798}
10799
10800/**
Daniel Veillard591b4be2003-02-09 23:33:36 +000010801 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010802 * @ctxt: the XPath Parser context
10803 *
10804 * [14] Expr ::= OrExpr
10805 * [21] OrExpr ::= AndExpr
10806 * | OrExpr 'or' AndExpr
10807 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010808 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +000010809 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010810static void
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010811xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010812 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010813 CHECK_ERROR;
10814 SKIP_BLANKS;
10815 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010816 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010817 SKIP(2);
10818 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010819 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010820 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010821 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10822 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +000010823 SKIP_BLANKS;
10824 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010825 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010826 /* more ops could be optimized too */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010827 /*
10828 * This is the main place to eliminate sorting for
10829 * operations which don't require a sorted node-set.
10830 * E.g. count().
10831 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010832 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10833 }
Owen Taylor3473f882001-02-23 17:55:21 +000010834}
10835
10836/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010837 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +000010838 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010839 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +000010840 *
10841 * [8] Predicate ::= '[' PredicateExpr ']'
10842 * [9] PredicateExpr ::= Expr
10843 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010844 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +000010845 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010846static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010847xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010848 int op1 = ctxt->comp->last;
10849
10850 SKIP_BLANKS;
10851 if (CUR != '[') {
10852 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10853 }
10854 NEXT;
10855 SKIP_BLANKS;
10856
10857 ctxt->comp->last = -1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000010858 /*
10859 * This call to xmlXPathCompileExpr() will deactivate sorting
10860 * of the predicate result.
10861 * TODO: Sorting is still activated for filters, since I'm not
10862 * sure if needed. Normally sorting should not be needed, since
10863 * a filter can only diminish the number of items in a sequence,
10864 * but won't change its order; so if the initial sequence is sorted,
10865 * subsequent sorting is not needed.
10866 */
10867 if (! filter)
10868 xmlXPathCompileExpr(ctxt, 0);
10869 else
10870 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010871 CHECK_ERROR;
10872
10873 if (CUR != ']') {
10874 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10875 }
10876
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010877 if (filter)
10878 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10879 else
10880 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010881
10882 NEXT;
10883 SKIP_BLANKS;
10884}
10885
10886/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010887 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +000010888 * @ctxt: the XPath Parser context
10889 * @test: pointer to a xmlXPathTestVal
10890 * @type: pointer to a xmlXPathTypeVal
10891 * @prefix: placeholder for a possible name prefix
10892 *
10893 * [7] NodeTest ::= NameTest
10894 * | NodeType '(' ')'
10895 * | 'processing-instruction' '(' Literal ')'
10896 *
10897 * [37] NameTest ::= '*'
10898 * | NCName ':' '*'
10899 * | QName
10900 * [38] NodeType ::= 'comment'
10901 * | 'text'
10902 * | 'processing-instruction'
10903 * | 'node'
10904 *
William M. Brack08171912003-12-29 02:52:11 +000010905 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +000010906 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010907static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010908xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10909 xmlXPathTypeVal *type, const xmlChar **prefix,
10910 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +000010911 int blanks;
10912
10913 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10914 STRANGE;
10915 return(NULL);
10916 }
William M. Brack78637da2003-07-31 14:47:38 +000010917 *type = (xmlXPathTypeVal) 0;
10918 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010919 *prefix = NULL;
10920 SKIP_BLANKS;
10921
10922 if ((name == NULL) && (CUR == '*')) {
10923 /*
10924 * All elements
10925 */
10926 NEXT;
10927 *test = NODE_TEST_ALL;
10928 return(NULL);
10929 }
10930
10931 if (name == NULL)
10932 name = xmlXPathParseNCName(ctxt);
10933 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010934 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010935 }
10936
William M. Brack76e95df2003-10-18 16:20:14 +000010937 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +000010938 SKIP_BLANKS;
10939 if (CUR == '(') {
10940 NEXT;
10941 /*
10942 * NodeType or PI search
10943 */
10944 if (xmlStrEqual(name, BAD_CAST "comment"))
10945 *type = NODE_TYPE_COMMENT;
10946 else if (xmlStrEqual(name, BAD_CAST "node"))
10947 *type = NODE_TYPE_NODE;
10948 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10949 *type = NODE_TYPE_PI;
10950 else if (xmlStrEqual(name, BAD_CAST "text"))
10951 *type = NODE_TYPE_TEXT;
10952 else {
10953 if (name != NULL)
10954 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000010955 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010956 }
10957
10958 *test = NODE_TEST_TYPE;
10959
10960 SKIP_BLANKS;
10961 if (*type == NODE_TYPE_PI) {
10962 /*
10963 * Specific case: search a PI by name.
10964 */
Owen Taylor3473f882001-02-23 17:55:21 +000010965 if (name != NULL)
10966 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +000010967 name = NULL;
10968 if (CUR != ')') {
10969 name = xmlXPathParseLiteral(ctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000010970 CHECK_ERROR NULL;
Daniel Veillarded23b7d2002-05-27 12:16:02 +000010971 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +000010972 SKIP_BLANKS;
10973 }
Owen Taylor3473f882001-02-23 17:55:21 +000010974 }
10975 if (CUR != ')') {
10976 if (name != NULL)
10977 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000010978 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010979 }
10980 NEXT;
10981 return(name);
10982 }
10983 *test = NODE_TEST_NAME;
10984 if ((!blanks) && (CUR == ':')) {
10985 NEXT;
10986
10987 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010988 * Since currently the parser context don't have a
10989 * namespace list associated:
10990 * The namespace name for this prefix can be computed
10991 * only at evaluation time. The compilation is done
10992 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +000010993 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010994#if 0
Owen Taylor3473f882001-02-23 17:55:21 +000010995 *prefix = xmlXPathNsLookup(ctxt->context, name);
10996 if (name != NULL)
10997 xmlFree(name);
10998 if (*prefix == NULL) {
10999 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11000 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011001#else
11002 *prefix = name;
11003#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011004
11005 if (CUR == '*') {
11006 /*
11007 * All elements
11008 */
11009 NEXT;
11010 *test = NODE_TEST_ALL;
11011 return(NULL);
11012 }
11013
11014 name = xmlXPathParseNCName(ctxt);
11015 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011016 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011017 }
11018 }
11019 return(name);
11020}
11021
11022/**
11023 * xmlXPathIsAxisName:
11024 * @name: a preparsed name token
11025 *
11026 * [6] AxisName ::= 'ancestor'
11027 * | 'ancestor-or-self'
11028 * | 'attribute'
11029 * | 'child'
11030 * | 'descendant'
11031 * | 'descendant-or-self'
11032 * | 'following'
11033 * | 'following-sibling'
11034 * | 'namespace'
11035 * | 'parent'
11036 * | 'preceding'
11037 * | 'preceding-sibling'
11038 * | 'self'
11039 *
11040 * Returns the axis or 0
11041 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011042static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +000011043xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +000011044 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011045 switch (name[0]) {
11046 case 'a':
11047 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11048 ret = AXIS_ANCESTOR;
11049 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11050 ret = AXIS_ANCESTOR_OR_SELF;
11051 if (xmlStrEqual(name, BAD_CAST "attribute"))
11052 ret = AXIS_ATTRIBUTE;
11053 break;
11054 case 'c':
11055 if (xmlStrEqual(name, BAD_CAST "child"))
11056 ret = AXIS_CHILD;
11057 break;
11058 case 'd':
11059 if (xmlStrEqual(name, BAD_CAST "descendant"))
11060 ret = AXIS_DESCENDANT;
11061 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11062 ret = AXIS_DESCENDANT_OR_SELF;
11063 break;
11064 case 'f':
11065 if (xmlStrEqual(name, BAD_CAST "following"))
11066 ret = AXIS_FOLLOWING;
11067 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11068 ret = AXIS_FOLLOWING_SIBLING;
11069 break;
11070 case 'n':
11071 if (xmlStrEqual(name, BAD_CAST "namespace"))
11072 ret = AXIS_NAMESPACE;
11073 break;
11074 case 'p':
11075 if (xmlStrEqual(name, BAD_CAST "parent"))
11076 ret = AXIS_PARENT;
11077 if (xmlStrEqual(name, BAD_CAST "preceding"))
11078 ret = AXIS_PRECEDING;
11079 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11080 ret = AXIS_PRECEDING_SIBLING;
11081 break;
11082 case 's':
11083 if (xmlStrEqual(name, BAD_CAST "self"))
11084 ret = AXIS_SELF;
11085 break;
11086 }
11087 return(ret);
11088}
11089
11090/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011091 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +000011092 * @ctxt: the XPath Parser context
11093 *
11094 * [4] Step ::= AxisSpecifier NodeTest Predicate*
11095 * | AbbreviatedStep
11096 *
11097 * [12] AbbreviatedStep ::= '.' | '..'
11098 *
11099 * [5] AxisSpecifier ::= AxisName '::'
11100 * | AbbreviatedAxisSpecifier
11101 *
11102 * [13] AbbreviatedAxisSpecifier ::= '@'?
11103 *
11104 * Modified for XPtr range support as:
11105 *
11106 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11107 * | AbbreviatedStep
11108 * | 'range-to' '(' Expr ')' Predicate*
11109 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011110 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +000011111 * A location step of . is short for self::node(). This is
11112 * particularly useful in conjunction with //. For example, the
11113 * location path .//para is short for
11114 * self::node()/descendant-or-self::node()/child::para
11115 * and so will select all para descendant elements of the context
11116 * node.
11117 * Similarly, a location step of .. is short for parent::node().
11118 * For example, ../title is short for parent::node()/child::title
11119 * and so will select the title children of the parent of the context
11120 * node.
11121 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011122static void
11123xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011124#ifdef LIBXML_XPTR_ENABLED
11125 int rangeto = 0;
11126 int op2 = -1;
11127#endif
11128
Owen Taylor3473f882001-02-23 17:55:21 +000011129 SKIP_BLANKS;
11130 if ((CUR == '.') && (NXT(1) == '.')) {
11131 SKIP(2);
11132 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011133 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11134 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011135 } else if (CUR == '.') {
11136 NEXT;
11137 SKIP_BLANKS;
11138 } else {
11139 xmlChar *name = NULL;
11140 const xmlChar *prefix = NULL;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011141 xmlXPathTestVal test = (xmlXPathTestVal) 0;
William M. Brack78637da2003-07-31 14:47:38 +000011142 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011143 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011144 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +000011145
11146 /*
11147 * The modification needed for XPointer change to the production
11148 */
11149#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011150 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +000011151 name = xmlXPathParseNCName(ctxt);
11152 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011153 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011154 xmlFree(name);
11155 SKIP_BLANKS;
11156 if (CUR != '(') {
11157 XP_ERROR(XPATH_EXPR_ERROR);
11158 }
11159 NEXT;
11160 SKIP_BLANKS;
11161
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011162 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011163 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +000011164 CHECK_ERROR;
11165
11166 SKIP_BLANKS;
11167 if (CUR != ')') {
11168 XP_ERROR(XPATH_EXPR_ERROR);
11169 }
11170 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011171 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000011172 goto eval_predicates;
11173 }
11174 }
11175#endif
Daniel Veillard2156a562001-04-28 12:24:34 +000011176 if (CUR == '*') {
11177 axis = AXIS_CHILD;
11178 } else {
11179 if (name == NULL)
11180 name = xmlXPathParseNCName(ctxt);
11181 if (name != NULL) {
11182 axis = xmlXPathIsAxisName(name);
11183 if (axis != 0) {
11184 SKIP_BLANKS;
11185 if ((CUR == ':') && (NXT(1) == ':')) {
11186 SKIP(2);
11187 xmlFree(name);
11188 name = NULL;
11189 } else {
11190 /* an element name can conflict with an axis one :-\ */
11191 axis = AXIS_CHILD;
11192 }
Owen Taylor3473f882001-02-23 17:55:21 +000011193 } else {
Owen Taylor3473f882001-02-23 17:55:21 +000011194 axis = AXIS_CHILD;
11195 }
Daniel Veillard2156a562001-04-28 12:24:34 +000011196 } else if (CUR == '@') {
11197 NEXT;
11198 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +000011199 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +000011200 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +000011201 }
Owen Taylor3473f882001-02-23 17:55:21 +000011202 }
11203
11204 CHECK_ERROR;
11205
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011206 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +000011207 if (test == 0)
11208 return;
11209
Daniel Veillarded6c5492005-07-23 15:00:22 +000011210 if ((prefix != NULL) && (ctxt->context != NULL) &&
11211 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11212 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11213 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11214 }
11215 }
Owen Taylor3473f882001-02-23 17:55:21 +000011216#ifdef DEBUG_STEP
11217 xmlGenericError(xmlGenericErrorContext,
11218 "Basis : computing new set\n");
11219#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011220
Owen Taylor3473f882001-02-23 17:55:21 +000011221#ifdef DEBUG_STEP
11222 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011223 if (ctxt->value == NULL)
11224 xmlGenericError(xmlGenericErrorContext, "no value\n");
11225 else if (ctxt->value->nodesetval == NULL)
11226 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11227 else
11228 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011229#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011230
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011231#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +000011232eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011233#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011234 op1 = ctxt->comp->last;
11235 ctxt->comp->last = -1;
11236
Owen Taylor3473f882001-02-23 17:55:21 +000011237 SKIP_BLANKS;
11238 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011239 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011240 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011241
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011242#ifdef LIBXML_XPTR_ENABLED
11243 if (rangeto) {
11244 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11245 } else
11246#endif
11247 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11248 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011249
Owen Taylor3473f882001-02-23 17:55:21 +000011250 }
11251#ifdef DEBUG_STEP
11252 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011253 if (ctxt->value == NULL)
11254 xmlGenericError(xmlGenericErrorContext, "no value\n");
11255 else if (ctxt->value->nodesetval == NULL)
11256 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11257 else
11258 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11259 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011260#endif
11261}
11262
11263/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011264 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011265 * @ctxt: the XPath Parser context
11266 *
11267 * [3] RelativeLocationPath ::= Step
11268 * | RelativeLocationPath '/' Step
11269 * | AbbreviatedRelativeLocationPath
11270 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
11271 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011272 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +000011273 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011274static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011275xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011276(xmlXPathParserContextPtr ctxt) {
11277 SKIP_BLANKS;
11278 if ((CUR == '/') && (NXT(1) == '/')) {
11279 SKIP(2);
11280 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011281 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11282 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011283 } else if (CUR == '/') {
11284 NEXT;
11285 SKIP_BLANKS;
11286 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011287 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011288 SKIP_BLANKS;
11289 while (CUR == '/') {
11290 if ((CUR == '/') && (NXT(1) == '/')) {
11291 SKIP(2);
11292 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011293 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +000011294 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011295 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011296 } else if (CUR == '/') {
11297 NEXT;
11298 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011299 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011300 }
11301 SKIP_BLANKS;
11302 }
11303}
11304
11305/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011306 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011307 * @ctxt: the XPath Parser context
11308 *
11309 * [1] LocationPath ::= RelativeLocationPath
11310 * | AbsoluteLocationPath
11311 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
11312 * | AbbreviatedAbsoluteLocationPath
11313 * [10] AbbreviatedAbsoluteLocationPath ::=
11314 * '//' RelativeLocationPath
11315 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011316 * Compile a location path
11317 *
Owen Taylor3473f882001-02-23 17:55:21 +000011318 * // is short for /descendant-or-self::node()/. For example,
11319 * //para is short for /descendant-or-self::node()/child::para and
11320 * so will select any para element in the document (even a para element
11321 * that is a document element will be selected by //para since the
11322 * document element node is a child of the root node); div//para is
11323 * short for div/descendant-or-self::node()/child::para and so will
11324 * select all para descendants of div children.
11325 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011326static void
11327xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000011328 SKIP_BLANKS;
11329 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011330 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011331 } else {
11332 while (CUR == '/') {
11333 if ((CUR == '/') && (NXT(1) == '/')) {
11334 SKIP(2);
11335 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011336 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11337 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011338 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011339 } else if (CUR == '/') {
11340 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +000011341 SKIP_BLANKS;
11342 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +000011343 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +000011344 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011345 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011346 }
11347 }
11348 }
11349}
11350
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011351/************************************************************************
11352 * *
11353 * XPath precompiled expression evaluation *
11354 * *
11355 ************************************************************************/
11356
Daniel Veillardf06307e2001-07-03 10:35:50 +000011357static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011358xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11359
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011360#ifdef DEBUG_STEP
11361static void
11362xmlXPathDebugDumpStepAxis(xmlXPathAxisVal axis,
11363 xmlXPathTestVal test,
11364 int nbNodes)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011365{
Daniel Veillardf06307e2001-07-03 10:35:50 +000011366 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011367 switch (axis) {
11368 case AXIS_ANCESTOR:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011369 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011370 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011371 case AXIS_ANCESTOR_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011372 xmlGenericError(xmlGenericErrorContext,
11373 "axis 'ancestors-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011374 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011375 case AXIS_ATTRIBUTE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011376 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011377 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011378 case AXIS_CHILD:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011379 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011380 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011381 case AXIS_DESCENDANT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011382 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011383 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011384 case AXIS_DESCENDANT_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011385 xmlGenericError(xmlGenericErrorContext,
11386 "axis 'descendant-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011387 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011388 case AXIS_FOLLOWING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011389 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011390 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011391 case AXIS_FOLLOWING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011392 xmlGenericError(xmlGenericErrorContext,
11393 "axis 'following-siblings' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011394 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011395 case AXIS_NAMESPACE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011396 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011397 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011398 case AXIS_PARENT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011399 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011400 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011401 case AXIS_PRECEDING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011402 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011403 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011404 case AXIS_PRECEDING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011405 xmlGenericError(xmlGenericErrorContext,
11406 "axis 'preceding-sibling' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011407 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011408 case AXIS_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011409 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011410 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011411 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011412 xmlGenericError(xmlGenericErrorContext,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011413 " context contains %d nodes\n", nbNodes);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011414 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011415 case NODE_TEST_NONE:
11416 xmlGenericError(xmlGenericErrorContext,
11417 " searching for none !!!\n");
11418 break;
11419 case NODE_TEST_TYPE:
11420 xmlGenericError(xmlGenericErrorContext,
11421 " searching for type %d\n", type);
11422 break;
11423 case NODE_TEST_PI:
11424 xmlGenericError(xmlGenericErrorContext,
11425 " searching for PI !!!\n");
11426 break;
11427 case NODE_TEST_ALL:
11428 xmlGenericError(xmlGenericErrorContext,
11429 " searching for *\n");
11430 break;
11431 case NODE_TEST_NS:
11432 xmlGenericError(xmlGenericErrorContext,
11433 " searching for namespace %s\n",
11434 prefix);
11435 break;
11436 case NODE_TEST_NAME:
11437 xmlGenericError(xmlGenericErrorContext,
11438 " searching for name %s\n", name);
11439 if (prefix != NULL)
11440 xmlGenericError(xmlGenericErrorContext,
11441 " with namespace %s\n", prefix);
11442 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011443 }
11444 xmlGenericError(xmlGenericErrorContext, "Testing : ");
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011445}
11446#endif /* DEBUG_STEP */
11447
11448static int
11449xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11450 xmlXPathStepOpPtr op,
11451 xmlNodeSetPtr set,
11452 int contextSize,
11453 int hasNsNodes)
11454{
11455 if (op->ch1 != -1) {
11456 xmlXPathCompExprPtr comp = ctxt->comp;
11457 /*
11458 * Process inner predicates first.
11459 */
11460 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11461 /*
11462 * TODO: raise an internal error.
11463 */
11464 }
11465 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11466 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11467 CHECK_ERROR0;
11468 if (contextSize <= 0)
11469 return(0);
11470 }
11471 if (op->ch2 != -1) {
11472 xmlXPathContextPtr xpctxt = ctxt->context;
11473 xmlNodePtr contextNode, oldContextNode;
11474 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011475 int i, res, contextPos = 0, newContextSize;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011476 xmlXPathStepOpPtr exprOp;
11477 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11478
11479#ifdef LIBXML_XPTR_ENABLED
11480 /*
11481 * URGENT TODO: Check the following:
11482 * We don't expect location sets if evaluating prediates, right?
11483 * Only filters should expect location sets, right?
11484 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011485#endif
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011486 /*
11487 * SPEC XPath 1.0:
11488 * "For each node in the node-set to be filtered, the
11489 * PredicateExpr is evaluated with that node as the
11490 * context node, with the number of nodes in the
11491 * node-set as the context size, and with the proximity
11492 * position of the node in the node-set with respect to
11493 * the axis as the context position;"
11494 * @oldset is the node-set" to be filtered.
11495 *
11496 * SPEC XPath 1.0:
11497 * "only predicates change the context position and
11498 * context size (see [2.4 Predicates])."
11499 * Example:
11500 * node-set context pos
11501 * nA 1
11502 * nB 2
11503 * nC 3
11504 * After applying predicate [position() > 1] :
11505 * node-set context pos
11506 * nB 1
11507 * nC 2
11508 */
11509 oldContextNode = xpctxt->node;
11510 oldContextDoc = xpctxt->doc;
11511 /*
11512 * Get the expression of this predicate.
11513 */
11514 exprOp = &ctxt->comp->steps[op->ch2];
11515 newContextSize = 0;
11516 for (i = 0; i < set->nodeNr; i++) {
11517 if (set->nodeTab[i] == NULL)
11518 continue;
11519
11520 contextNode = set->nodeTab[i];
11521 xpctxt->node = contextNode;
11522 xpctxt->contextSize = contextSize;
11523 xpctxt->proximityPosition = ++contextPos;
11524
11525 /*
11526 * Also set the xpath document in case things like
11527 * key() are evaluated in the predicate.
11528 */
11529 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11530 (contextNode->doc != NULL))
11531 xpctxt->doc = contextNode->doc;
11532 /*
11533 * Evaluate the predicate expression with 1 context node
11534 * at a time; this node is packaged into a node set; this
11535 * node set is handed over to the evaluation mechanism.
11536 */
11537 if (contextObj == NULL)
11538 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11539 else
11540 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11541 contextNode);
11542
11543 valuePush(ctxt, contextObj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011544
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011545 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp);
11546
11547 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1))
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011548 goto evaluation_error;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011549
11550 if (res != 0) {
11551 newContextSize++;
11552 } else {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011553 /*
11554 * Remove the entry from the initial node set.
11555 */
11556 set->nodeTab[i] = NULL;
11557 if (contextNode->type == XML_NAMESPACE_DECL)
11558 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011559 }
11560 if (ctxt->value == contextObj) {
11561 /*
11562 * Don't free the temporary XPath object holding the
11563 * context node, in order to avoid massive recreation
11564 * inside this loop.
11565 */
11566 valuePop(ctxt);
11567 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11568 } else {
11569 /*
11570 * TODO: The object was lost in the evaluation machinery.
11571 * Can this happen? Maybe in internal-error cases.
11572 */
11573 contextObj = NULL;
11574 }
11575 }
11576 goto evaluation_exit;
11577
11578evaluation_error:
11579 xmlXPathNodeSetClear(set, hasNsNodes);
11580 newContextSize = 0;
11581
11582evaluation_exit:
11583 if (contextObj != NULL) {
11584 if (ctxt->value == contextObj)
11585 valuePop(ctxt);
11586 xmlXPathReleaseObject(xpctxt, contextObj);
11587 }
11588 if (exprRes != NULL)
11589 xmlXPathReleaseObject(ctxt->context, exprRes);
11590 /*
11591 * Reset/invalidate the context.
11592 */
11593 xpctxt->node = oldContextNode;
11594 xpctxt->doc = oldContextDoc;
11595 xpctxt->contextSize = -1;
11596 xpctxt->proximityPosition = -1;
11597 return(newContextSize);
11598 }
11599 return(contextSize);
11600}
11601
11602static int
11603xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11604 xmlXPathStepOpPtr op,
11605 xmlNodeSetPtr set,
11606 int contextSize,
11607 int minPos,
11608 int maxPos,
11609 int hasNsNodes)
11610{
11611 if (op->ch1 != -1) {
11612 xmlXPathCompExprPtr comp = ctxt->comp;
11613 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11614 /*
11615 * TODO: raise an internal error.
11616 */
11617 }
11618 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11619 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11620 CHECK_ERROR0;
11621 if (contextSize <= 0)
11622 return(0);
11623 }
11624 /*
11625 * Check if the node set contains a sufficient number of nodes for
11626 * the requested range.
11627 */
11628 if (contextSize < minPos) {
11629 xmlXPathNodeSetClear(set, hasNsNodes);
11630 return(0);
11631 }
11632 if (op->ch2 == -1) {
11633 /*
11634 * TODO: Can this ever happen?
11635 */
11636 return (contextSize);
11637 } else {
11638 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011639 int i, pos = 0, newContextSize = 0, contextPos = 0, res;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011640 xmlXPathStepOpPtr exprOp;
11641 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11642 xmlNodePtr oldContextNode, contextNode = NULL;
11643 xmlXPathContextPtr xpctxt = ctxt->context;
11644
11645#ifdef LIBXML_XPTR_ENABLED
11646 /*
11647 * URGENT TODO: Check the following:
11648 * We don't expect location sets if evaluating prediates, right?
11649 * Only filters should expect location sets, right?
11650 */
11651#endif /* LIBXML_XPTR_ENABLED */
11652
11653 /*
11654 * Save old context.
11655 */
11656 oldContextNode = xpctxt->node;
11657 oldContextDoc = xpctxt->doc;
11658 /*
11659 * Get the expression of this predicate.
11660 */
11661 exprOp = &ctxt->comp->steps[op->ch2];
11662 for (i = 0; i < set->nodeNr; i++) {
11663 if (set->nodeTab[i] == NULL)
11664 continue;
11665
11666 contextNode = set->nodeTab[i];
11667 xpctxt->node = contextNode;
11668 xpctxt->contextSize = contextSize;
11669 xpctxt->proximityPosition = ++contextPos;
11670
11671 /*
11672 * Initialize the new set.
11673 * Also set the xpath document in case things like
11674 * key() evaluation are attempted on the predicate
11675 */
11676 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11677 (contextNode->doc != NULL))
11678 xpctxt->doc = contextNode->doc;
11679 /*
11680 * Evaluate the predicate expression with 1 context node
11681 * at a time; this node is packaged into a node set; this
11682 * node set is handed over to the evaluation mechanism.
11683 */
11684 if (contextObj == NULL)
11685 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11686 else
11687 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11688 contextNode);
11689
11690 valuePush(ctxt, contextObj);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011691 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp);
11692
11693 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1))
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011694 goto evaluation_error;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011695
11696 if (res)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011697 pos++;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011698
11699 if (res && (pos >= minPos) && (pos <= maxPos)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011700 /*
11701 * Fits in the requested range.
11702 */
11703 newContextSize++;
11704 if (minPos == maxPos) {
11705 /*
11706 * Only 1 node was requested.
11707 */
11708 if (contextNode->type == XML_NAMESPACE_DECL) {
11709 /*
11710 * As always: take care of those nasty
11711 * namespace nodes.
11712 */
11713 set->nodeTab[i] = NULL;
11714 }
11715 xmlXPathNodeSetClear(set, hasNsNodes);
11716 set->nodeNr = 1;
11717 set->nodeTab[0] = contextNode;
11718 goto evaluation_exit;
11719 }
11720 if (pos == maxPos) {
11721 /*
11722 * We are done.
11723 */
11724 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11725 goto evaluation_exit;
11726 }
11727 } else {
11728 /*
11729 * Remove the entry from the initial node set.
11730 */
11731 set->nodeTab[i] = NULL;
11732 if (contextNode->type == XML_NAMESPACE_DECL)
11733 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11734 }
11735 if (exprRes != NULL) {
11736 xmlXPathReleaseObject(ctxt->context, exprRes);
11737 exprRes = NULL;
11738 }
11739 if (ctxt->value == contextObj) {
11740 /*
11741 * Don't free the temporary XPath object holding the
11742 * context node, in order to avoid massive recreation
11743 * inside this loop.
11744 */
11745 valuePop(ctxt);
11746 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11747 } else {
11748 /*
11749 * The object was lost in the evaluation machinery.
11750 * Can this happen? Maybe in case of internal-errors.
11751 */
11752 contextObj = NULL;
11753 }
11754 }
11755 goto evaluation_exit;
11756
11757evaluation_error:
11758 xmlXPathNodeSetClear(set, hasNsNodes);
11759 newContextSize = 0;
11760
11761evaluation_exit:
11762 if (contextObj != NULL) {
11763 if (ctxt->value == contextObj)
11764 valuePop(ctxt);
11765 xmlXPathReleaseObject(xpctxt, contextObj);
11766 }
11767 if (exprRes != NULL)
11768 xmlXPathReleaseObject(ctxt->context, exprRes);
11769 /*
11770 * Reset/invalidate the context.
11771 */
11772 xpctxt->node = oldContextNode;
11773 xpctxt->doc = oldContextDoc;
11774 xpctxt->contextSize = -1;
11775 xpctxt->proximityPosition = -1;
11776 return(newContextSize);
11777 }
11778 return(contextSize);
11779}
11780
11781static int
11782xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11783 xmlXPathStepOpPtr op,
11784 int *maxPos)
11785{
11786
11787 xmlXPathStepOpPtr exprOp;
11788
11789 /*
11790 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11791 */
11792
11793 /*
11794 * If not -1, then ch1 will point to:
11795 * 1) For predicates (XPATH_OP_PREDICATE):
11796 * - an inner predicate operator
11797 * 2) For filters (XPATH_OP_FILTER):
11798 * - an inner filter operater OR
11799 * - an expression selecting the node set.
11800 * E.g. "key('a', 'b')" or "(//foo | //bar)".
11801 */
11802 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11803 return(0);
11804
11805 if (op->ch2 != -1) {
11806 exprOp = &ctxt->comp->steps[op->ch2];
11807 } else
11808 return(0);
11809
11810 if ((exprOp != NULL) &&
11811 (exprOp->op == XPATH_OP_VALUE) &&
11812 (exprOp->value4 != NULL) &&
11813 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11814 {
11815 /*
11816 * We have a "[n]" predicate here.
11817 * TODO: Unfortunately this simplistic test here is not
11818 * able to detect a position() predicate in compound
11819 * expressions like "[@attr = 'a" and position() = 1],
11820 * and even not the usage of position() in
11821 * "[position() = 1]"; thus - obviously - a position-range,
11822 * like it "[position() < 5]", is also not detected.
11823 * Maybe we could rewrite the AST to ease the optimization.
11824 */
11825 *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11826
11827 if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
11828 (float) *maxPos)
11829 {
11830 return(1);
11831 }
11832 }
11833 return(0);
11834}
11835
11836static int
11837xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11838 xmlXPathStepOpPtr op,
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011839 xmlNodePtr * first, xmlNodePtr * last,
11840 int toBool)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011841{
11842
11843#define XP_TEST_HIT \
11844 if (hasAxisRange != 0) { \
11845 if (++pos == maxPos) { \
11846 addNode(seq, cur); \
11847 goto axis_range_end; } \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011848 } else { \
11849 addNode(seq, cur); \
11850 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011851
11852#define XP_TEST_HIT_NS \
11853 if (hasAxisRange != 0) { \
11854 if (++pos == maxPos) { \
11855 hasNsNodes = 1; \
11856 xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
11857 goto axis_range_end; } \
11858 } else { \
11859 hasNsNodes = 1; \
11860 xmlXPathNodeSetAddNs(seq, \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011861 xpctxt->node, (xmlNsPtr) cur); \
11862 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011863
11864 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11865 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11866 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11867 const xmlChar *prefix = op->value4;
11868 const xmlChar *name = op->value5;
11869 const xmlChar *URI = NULL;
11870
11871#ifdef DEBUG_STEP
11872 int nbMatches = 0, prevMatches = 0;
11873#endif
11874 int total = 0, hasNsNodes = 0;
11875 /* The popped object holding the context nodes */
11876 xmlXPathObjectPtr obj;
11877 /* The set of context nodes for the node tests */
11878 xmlNodeSetPtr contextSeq;
11879 int contextIdx;
11880 xmlNodePtr contextNode;
11881 /* The context node for a compound traversal */
11882 xmlNodePtr outerContextNode;
11883 /* The final resulting node set wrt to all context nodes */
11884 xmlNodeSetPtr outSeq;
11885 /*
11886 * The temporary resulting node set wrt 1 context node.
11887 * Used to feed predicate evaluation.
11888 */
11889 xmlNodeSetPtr seq;
11890 xmlNodePtr cur;
11891 /* First predicate operator */
11892 xmlXPathStepOpPtr predOp;
11893 int maxPos; /* The requested position() (when a "[n]" predicate) */
11894 int hasPredicateRange, hasAxisRange, pos, size, newSize;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011895 int breakOnFirstHit;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011896
11897 xmlXPathTraversalFunction next = NULL;
11898 /* compound axis traversal */
11899 xmlXPathTraversalFunctionExt outerNext = NULL;
11900 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
11901 xmlXPathNodeSetMergeFunction mergeAndClear;
11902 xmlNodePtr oldContextNode;
11903 xmlXPathContextPtr xpctxt = ctxt->context;
11904
11905
11906 CHECK_TYPE0(XPATH_NODESET);
11907 obj = valuePop(ctxt);
11908 /*
11909 * Setup namespaces.
11910 */
11911 if (prefix != NULL) {
11912 URI = xmlXPathNsLookup(xpctxt, prefix);
11913 if (URI == NULL) {
11914 xmlXPathReleaseObject(xpctxt, obj);
11915 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11916 }
11917 }
11918 /*
11919 * Setup axis.
11920 *
11921 * MAYBE FUTURE TODO: merging optimizations:
11922 * - If the nodes to be traversed wrt to the initial nodes and
11923 * the current axis cannot overlap, then we could avoid searching
11924 * for duplicates during the merge.
11925 * But the question is how/when to evaluate if they cannot overlap.
11926 * Example: if we know that for two initial nodes, the one is
11927 * not in the ancestor-or-self axis of the other, then we could safely
11928 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
11929 * the descendant-or-self axis.
11930 */
11931 addNode = xmlXPathNodeSetAdd;
11932 mergeAndClear = xmlXPathNodeSetMergeAndClear;
11933 switch (axis) {
11934 case AXIS_ANCESTOR:
11935 first = NULL;
11936 next = xmlXPathNextAncestor;
11937 break;
11938 case AXIS_ANCESTOR_OR_SELF:
11939 first = NULL;
11940 next = xmlXPathNextAncestorOrSelf;
11941 break;
11942 case AXIS_ATTRIBUTE:
11943 first = NULL;
11944 last = NULL;
11945 next = xmlXPathNextAttribute;
11946 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11947 break;
11948 case AXIS_CHILD:
11949 last = NULL;
11950 if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
11951 /*
11952 * This iterator will give us only nodes which can
11953 * hold element nodes.
11954 */
11955 outerNext = xmlXPathNextDescendantOrSelfElemParent;
11956 }
11957 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
11958 (type == NODE_TYPE_NODE))
11959 {
11960 /*
11961 * Optimization if an element node type is 'element'.
11962 */
11963 next = xmlXPathNextChildElement;
11964 } else
11965 next = xmlXPathNextChild;
11966 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11967 break;
11968 case AXIS_DESCENDANT:
11969 last = NULL;
11970 next = xmlXPathNextDescendant;
11971 break;
11972 case AXIS_DESCENDANT_OR_SELF:
11973 last = NULL;
11974 next = xmlXPathNextDescendantOrSelf;
11975 break;
11976 case AXIS_FOLLOWING:
11977 last = NULL;
11978 next = xmlXPathNextFollowing;
11979 break;
11980 case AXIS_FOLLOWING_SIBLING:
11981 last = NULL;
11982 next = xmlXPathNextFollowingSibling;
11983 break;
11984 case AXIS_NAMESPACE:
11985 first = NULL;
11986 last = NULL;
11987 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
11988 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11989 break;
11990 case AXIS_PARENT:
11991 first = NULL;
11992 next = xmlXPathNextParent;
11993 break;
11994 case AXIS_PRECEDING:
11995 first = NULL;
11996 next = xmlXPathNextPrecedingInternal;
11997 break;
11998 case AXIS_PRECEDING_SIBLING:
11999 first = NULL;
12000 next = xmlXPathNextPrecedingSibling;
12001 break;
12002 case AXIS_SELF:
12003 first = NULL;
12004 last = NULL;
12005 next = xmlXPathNextSelf;
12006 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12007 break;
12008 }
12009
12010#ifdef DEBUG_STEP
12011 xmlXPathDebugDumpStepAxis(axis, test,
12012 (obj->nodesetval != NULL) ? obj->nodsetval->nodeNr : 0);
12013#endif
12014
12015 if (next == NULL) {
12016 xmlXPathReleaseObject(xpctxt, obj);
12017 return(0);
12018 }
12019 contextSeq = obj->nodesetval;
12020 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12021 xmlXPathReleaseObject(xpctxt, obj);
12022 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12023 return(0);
12024 }
12025 /*
12026 * Predicate optimization ---------------------------------------------
12027 * If this step has a last predicate, which contains a position(),
12028 * then we'll optimize (although not exactly "position()", but only
12029 * the short-hand form, i.e., "[n]".
12030 *
12031 * Example - expression "/foo[parent::bar][1]":
12032 *
12033 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12034 * ROOT -- op->ch1
12035 * PREDICATE -- op->ch2 (predOp)
12036 * PREDICATE -- predOp->ch1 = [parent::bar]
12037 * SORT
12038 * COLLECT 'parent' 'name' 'node' bar
12039 * NODE
12040 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12041 *
12042 */
12043 maxPos = 0;
12044 predOp = NULL;
12045 hasPredicateRange = 0;
12046 hasAxisRange = 0;
12047 if (op->ch2 != -1) {
12048 /*
12049 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12050 */
12051 predOp = &ctxt->comp->steps[op->ch2];
12052 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12053 if (predOp->ch1 != -1) {
12054 /*
12055 * Use the next inner predicate operator.
12056 */
12057 predOp = &ctxt->comp->steps[predOp->ch1];
12058 hasPredicateRange = 1;
12059 } else {
12060 /*
12061 * There's no other predicate than the [n] predicate.
12062 */
12063 predOp = NULL;
12064 hasAxisRange = 1;
12065 }
12066 }
12067 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012068 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012069 /*
12070 * Axis traversal -----------------------------------------------------
12071 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012072 /*
12073 * 2.3 Node Tests
12074 * - For the attribute axis, the principal node type is attribute.
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012075 * - For the namespace axis, the principal node type is namespace.
12076 * - For other axes, the principal node type is element.
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012077 *
12078 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012079 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012080 * select all element children of the context node
12081 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012082 oldContextNode = xpctxt->node;
12083 addNode = xmlXPathNodeSetAddUnique;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012084 outSeq = NULL;
12085 seq = NULL;
12086 outerContextNode = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012087 contextNode = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012088 contextIdx = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012089
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012090
12091 while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
12092 if (outerNext != NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012093 /*
12094 * This is a compound traversal.
12095 */
12096 if (contextNode == NULL) {
12097 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012098 * Set the context for the outer traversal.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012099 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012100 outerContextNode = contextSeq->nodeTab[contextIdx++];
12101 contextNode = outerNext(NULL, outerContextNode);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012102 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012103 contextNode = outerNext(contextNode, outerContextNode);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012104 if (contextNode == NULL)
12105 continue;
12106 /*
12107 * Set the context for the main traversal.
12108 */
12109 xpctxt->node = contextNode;
12110 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012111 xpctxt->node = contextSeq->nodeTab[contextIdx++];
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012112
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012113 if (seq == NULL) {
12114 seq = xmlXPathNodeSetCreate(NULL);
12115 if (seq == NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012116 total = 0;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012117 goto error;
12118 }
12119 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012120 /*
12121 * Traverse the axis and test the nodes.
12122 */
12123 pos = 0;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012124 cur = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012125 hasNsNodes = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012126 do {
12127 cur = next(ctxt, cur);
12128 if (cur == NULL)
12129 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012130
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012131 /*
12132 * QUESTION TODO: What does the "first" and "last" stuff do?
12133 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012134 if ((first != NULL) && (*first != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012135 if (*first == cur)
12136 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012137 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012138#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012139 (xmlXPathCmpNodesExt(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012140#else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012141 (xmlXPathCmpNodes(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012142#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012143 {
12144 break;
12145 }
12146 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012147 if ((last != NULL) && (*last != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012148 if (*last == cur)
12149 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012150 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012151#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012152 (xmlXPathCmpNodesExt(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012153#else
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012154 (xmlXPathCmpNodes(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012155#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012156 {
12157 break;
12158 }
12159 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012160
12161 total++;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012162
Daniel Veillardf06307e2001-07-03 10:35:50 +000012163#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012164 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12165#endif
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012166 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012167 case NODE_TEST_NONE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012168 total = 0;
12169 STRANGE
12170 goto error;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012171 case NODE_TEST_TYPE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012172 /*
12173 * TODO: Don't we need to use
12174 * xmlXPathNodeSetAddNs() for namespace nodes here?
12175 * Surprisingly, some c14n tests fail, if we do this.
12176 */
12177 if (type == NODE_TYPE_NODE) {
12178 switch (cur->type) {
12179 case XML_DOCUMENT_NODE:
12180 case XML_HTML_DOCUMENT_NODE:
12181#ifdef LIBXML_DOCB_ENABLED
12182 case XML_DOCB_DOCUMENT_NODE:
12183#endif
12184 case XML_ELEMENT_NODE:
12185 case XML_ATTRIBUTE_NODE:
12186 case XML_PI_NODE:
12187 case XML_COMMENT_NODE:
12188 case XML_CDATA_SECTION_NODE:
12189 case XML_TEXT_NODE:
12190 case XML_NAMESPACE_DECL:
12191 XP_TEST_HIT
12192 break;
12193 default:
12194 break;
12195 }
12196 } else if (cur->type == type) {
12197 XP_TEST_HIT
12198 } else if ((type == NODE_TYPE_TEXT) &&
12199 (cur->type == XML_CDATA_SECTION_NODE))
12200 {
12201 XP_TEST_HIT
12202 }
12203 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012204 case NODE_TEST_PI:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012205 if ((cur->type == XML_PI_NODE) &&
12206 ((name == NULL) || xmlStrEqual(name, cur->name)))
12207 {
12208 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012209 }
12210 break;
12211 case NODE_TEST_ALL:
12212 if (axis == AXIS_ATTRIBUTE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012213 if (cur->type == XML_ATTRIBUTE_NODE)
12214 {
12215 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012216 }
12217 } else if (axis == AXIS_NAMESPACE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012218 if (cur->type == XML_NAMESPACE_DECL)
12219 {
12220 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012221 }
12222 } else {
12223 if (cur->type == XML_ELEMENT_NODE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012224 if (prefix == NULL)
12225 {
12226 XP_TEST_HIT
12227
Daniel Veillardf06307e2001-07-03 10:35:50 +000012228 } else if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012229 (xmlStrEqual(URI, cur->ns->href)))
12230 {
12231 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012232 }
12233 }
12234 }
12235 break;
12236 case NODE_TEST_NS:{
12237 TODO;
12238 break;
12239 }
12240 case NODE_TEST_NAME:
12241 switch (cur->type) {
12242 case XML_ELEMENT_NODE:
12243 if (xmlStrEqual(name, cur->name)) {
12244 if (prefix == NULL) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012245 if (cur->ns == NULL)
12246 {
12247 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012248 }
12249 } else {
12250 if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012251 (xmlStrEqual(URI, cur->ns->href)))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012252 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012253 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012254 }
12255 }
12256 }
12257 break;
12258 case XML_ATTRIBUTE_NODE:{
12259 xmlAttrPtr attr = (xmlAttrPtr) cur;
12260
12261 if (xmlStrEqual(name, attr->name)) {
12262 if (prefix == NULL) {
12263 if ((attr->ns == NULL) ||
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012264 (attr->ns->prefix == NULL))
12265 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012266 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012267 }
12268 } else {
12269 if ((attr->ns != NULL) &&
12270 (xmlStrEqual(URI,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012271 attr->ns->href)))
12272 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012273 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012274 }
12275 }
12276 }
12277 break;
12278 }
12279 case XML_NAMESPACE_DECL:
12280 if (cur->type == XML_NAMESPACE_DECL) {
12281 xmlNsPtr ns = (xmlNsPtr) cur;
12282
12283 if ((ns->prefix != NULL) && (name != NULL)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012284 && (xmlStrEqual(ns->prefix, name)))
12285 {
12286 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012287 }
12288 }
12289 break;
12290 default:
12291 break;
12292 }
12293 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012294 } /* switch(test) */
12295 } while (cur != NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012296
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012297 goto apply_predicates;
12298
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012299axis_range_end: /* ----------------------------------------------------- */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012300 /*
12301 * We have a "/foo[n]", and position() = n was reached.
12302 * Note that we can have as well "/foo/::parent::foo[1]", so
12303 * a duplicate-aware merge is still needed.
12304 * Merge with the result.
12305 */
12306 if (outSeq == NULL) {
12307 outSeq = seq;
12308 seq = NULL;
12309 } else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012310 outSeq = mergeAndClear(outSeq, seq, 0);
12311 /*
12312 * Break if only a true/false result was requested.
12313 */
12314 if (toBool)
12315 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012316 continue;
12317
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012318first_hit: /* ---------------------------------------------------------- */
12319 /*
12320 * Break if only a true/false result was requested and
12321 * no predicates existed and a node test succeeded.
12322 */
12323 if (outSeq == NULL) {
12324 outSeq = seq;
12325 seq = NULL;
12326 } else
12327 outSeq = mergeAndClear(outSeq, seq, 0);
12328 break;
12329
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012330#ifdef DEBUG_STEP
12331 if (seq != NULL)
12332 nbMatches += seq->nodeNr;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012333#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012334
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012335apply_predicates: /* --------------------------------------------------- */
12336 /*
12337 * Apply predicates.
12338 */
12339 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12340 /*
12341 * E.g. when we have a "/foo[some expression][n]".
12342 */
12343 /*
12344 * QUESTION TODO: The old predicate evaluation took into
12345 * account location-sets.
12346 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12347 * Do we expect such a set here?
12348 * All what I learned now from the evaluation semantics
12349 * does not indicate that a location-set will be processed
12350 * here, so this looks OK.
12351 */
12352 /*
12353 * Iterate over all predicates, starting with the outermost
12354 * predicate.
12355 * TODO: Problem: we cannot execute the inner predicates first
12356 * since we cannot go back *up* the operator tree!
12357 * Options we have:
12358 * 1) Use of recursive functions (like is it currently done
12359 * via xmlXPathCompOpEval())
12360 * 2) Add a predicate evaluation information stack to the
12361 * context struct
12362 * 3) Change the way the operators are linked; we need a
12363 * "parent" field on xmlXPathStepOp
12364 *
12365 * For the moment, I'll try to solve this with a recursive
12366 * function: xmlXPathCompOpEvalPredicate().
12367 */
12368 size = seq->nodeNr;
12369 if (hasPredicateRange != 0)
12370 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12371 predOp, seq, size, maxPos, maxPos, hasNsNodes);
12372 else
12373 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12374 predOp, seq, size, hasNsNodes);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012375
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012376 if (ctxt->error != XPATH_EXPRESSION_OK) {
12377 total = 0;
12378 goto error;
12379 }
12380 /*
12381 * Add the filtered set of nodes to the result node set.
12382 */
12383 if (newSize == 0) {
12384 /*
12385 * The predicates filtered all nodes out.
12386 */
12387 xmlXPathNodeSetClear(seq, hasNsNodes);
12388 } else if (seq->nodeNr > 0) {
12389 /*
12390 * Add to result set.
12391 */
12392 if (outSeq == NULL) {
12393 if (size != newSize) {
12394 /*
12395 * We need to merge and clear here, since
12396 * the sequence will contained NULLed entries.
12397 */
12398 outSeq = mergeAndClear(NULL, seq, 1);
12399 } else {
12400 outSeq = seq;
12401 seq = NULL;
12402 }
12403 } else
12404 outSeq = mergeAndClear(outSeq, seq,
12405 (size != newSize) ? 1: 0);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012406 /*
12407 * Break if only a true/false result was requested.
12408 */
12409 if (toBool)
12410 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012411 }
12412 } else if (seq->nodeNr > 0) {
12413 /*
12414 * Add to result set.
12415 */
12416 if (outSeq == NULL) {
12417 outSeq = seq;
12418 seq = NULL;
12419 } else {
12420 outSeq = mergeAndClear(outSeq, seq, 0);
12421 }
12422 }
12423 }
12424
12425error:
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012426 if ((obj->boolval) && (obj->user != NULL)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012427 /*
12428 * QUESTION TODO: What does this do and why?
12429 * TODO: Do we have to do this also for the "error"
12430 * cleanup further down?
12431 */
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012432 ctxt->value->boolval = 1;
12433 ctxt->value->user = obj->user;
12434 obj->user = NULL;
12435 obj->boolval = 0;
12436 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012437 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012438
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012439 /*
12440 * Ensure we return at least an emtpy set.
12441 */
12442 if (outSeq == NULL) {
12443 if ((seq != NULL) && (seq->nodeNr == 0))
12444 outSeq = seq;
12445 else
12446 outSeq = xmlXPathNodeSetCreate(NULL);
12447 }
12448 if ((seq != NULL) && (seq != outSeq)) {
12449 xmlXPathFreeNodeSet(seq);
12450 }
12451 /*
12452 * Hand over the result. Better to push the set also in
12453 * case of errors.
12454 */
12455 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12456 /*
12457 * Reset the context node.
12458 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012459 xpctxt->node = oldContextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012460
12461#ifdef DEBUG_STEP
12462 xmlGenericError(xmlGenericErrorContext,
12463 "\nExamined %d nodes, found %d nodes at that step\n",
12464 total, nbMatches);
12465#endif
12466
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012467 return(total);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012468}
12469
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012470static int
12471xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12472 xmlXPathStepOpPtr op, xmlNodePtr * first);
12473
Daniel Veillardf06307e2001-07-03 10:35:50 +000012474/**
12475 * xmlXPathCompOpEvalFirst:
12476 * @ctxt: the XPath parser context with the compiled expression
12477 * @op: an XPath compiled operation
12478 * @first: the first elem found so far
12479 *
12480 * Evaluate the Precompiled XPath operation searching only the first
12481 * element in document order
12482 *
12483 * Returns the number of examined objects.
12484 */
12485static int
12486xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12487 xmlXPathStepOpPtr op, xmlNodePtr * first)
12488{
12489 int total = 0, cur;
12490 xmlXPathCompExprPtr comp;
12491 xmlXPathObjectPtr arg1, arg2;
12492
Daniel Veillard556c6682001-10-06 09:59:51 +000012493 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012494 comp = ctxt->comp;
12495 switch (op->op) {
12496 case XPATH_OP_END:
12497 return (0);
12498 case XPATH_OP_UNION:
12499 total =
12500 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12501 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012502 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012503 if ((ctxt->value != NULL)
12504 && (ctxt->value->type == XPATH_NODESET)
12505 && (ctxt->value->nodesetval != NULL)
12506 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12507 /*
12508 * limit tree traversing to first node in the result
12509 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012510 /*
12511 * OPTIMIZE TODO: This implicitely sorts
12512 * the result, even if not needed. E.g. if the argument
12513 * of the count() function, no sorting is needed.
12514 * OPTIMIZE TODO: How do we know if the node-list wasn't
12515 * aready sorted?
12516 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012517 if (ctxt->value->nodesetval->nodeNr > 1)
12518 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012519 *first = ctxt->value->nodesetval->nodeTab[0];
12520 }
12521 cur =
12522 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12523 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012524 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012525 CHECK_TYPE0(XPATH_NODESET);
12526 arg2 = valuePop(ctxt);
12527
12528 CHECK_TYPE0(XPATH_NODESET);
12529 arg1 = valuePop(ctxt);
12530
12531 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12532 arg2->nodesetval);
12533 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012534 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012535 /* optimizer */
12536 if (total > cur)
12537 xmlXPathCompSwap(op);
12538 return (total + cur);
12539 case XPATH_OP_ROOT:
12540 xmlXPathRoot(ctxt);
12541 return (0);
12542 case XPATH_OP_NODE:
12543 if (op->ch1 != -1)
12544 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012545 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012546 if (op->ch2 != -1)
12547 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012548 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012549 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12550 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012551 return (total);
12552 case XPATH_OP_RESET:
12553 if (op->ch1 != -1)
12554 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012555 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012556 if (op->ch2 != -1)
12557 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012558 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012559 ctxt->context->node = NULL;
12560 return (total);
12561 case XPATH_OP_COLLECT:{
12562 if (op->ch1 == -1)
12563 return (total);
12564
12565 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012566 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012567
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012568 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012569 return (total);
12570 }
12571 case XPATH_OP_VALUE:
12572 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012573 xmlXPathCacheObjectCopy(ctxt->context,
12574 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012575 return (0);
12576 case XPATH_OP_SORT:
12577 if (op->ch1 != -1)
12578 total +=
12579 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12580 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012581 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012582 if ((ctxt->value != NULL)
12583 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012584 && (ctxt->value->nodesetval != NULL)
12585 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012586 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12587 return (total);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012588#ifdef XP_OPTIMIZED_FILTER_FIRST
12589 case XPATH_OP_FILTER:
12590 total =+ xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12591 return (total);
12592#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000012593 default:
12594 return (xmlXPathCompOpEval(ctxt, op));
12595 }
12596}
12597
12598/**
12599 * xmlXPathCompOpEvalLast:
12600 * @ctxt: the XPath parser context with the compiled expression
12601 * @op: an XPath compiled operation
12602 * @last: the last elem found so far
12603 *
12604 * Evaluate the Precompiled XPath operation searching only the last
12605 * element in document order
12606 *
William M. Brack08171912003-12-29 02:52:11 +000012607 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000012608 */
12609static int
12610xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12611 xmlNodePtr * last)
12612{
12613 int total = 0, cur;
12614 xmlXPathCompExprPtr comp;
12615 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +000012616 xmlNodePtr bak;
12617 xmlDocPtr bakd;
12618 int pp;
12619 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012620
Daniel Veillard556c6682001-10-06 09:59:51 +000012621 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012622 comp = ctxt->comp;
12623 switch (op->op) {
12624 case XPATH_OP_END:
12625 return (0);
12626 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +000012627 bakd = ctxt->context->doc;
12628 bak = ctxt->context->node;
12629 pp = ctxt->context->proximityPosition;
12630 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012631 total =
12632 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012633 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012634 if ((ctxt->value != NULL)
12635 && (ctxt->value->type == XPATH_NODESET)
12636 && (ctxt->value->nodesetval != NULL)
12637 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12638 /*
12639 * limit tree traversing to first node in the result
12640 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012641 if (ctxt->value->nodesetval->nodeNr > 1)
12642 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012643 *last =
12644 ctxt->value->nodesetval->nodeTab[ctxt->value->
12645 nodesetval->nodeNr -
12646 1];
12647 }
William M. Brackce4fc562004-01-22 02:47:18 +000012648 ctxt->context->doc = bakd;
12649 ctxt->context->node = bak;
12650 ctxt->context->proximityPosition = pp;
12651 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012652 cur =
12653 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012654 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012655 if ((ctxt->value != NULL)
12656 && (ctxt->value->type == XPATH_NODESET)
12657 && (ctxt->value->nodesetval != NULL)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012658 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012659 }
12660 CHECK_TYPE0(XPATH_NODESET);
12661 arg2 = valuePop(ctxt);
12662
12663 CHECK_TYPE0(XPATH_NODESET);
12664 arg1 = valuePop(ctxt);
12665
12666 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12667 arg2->nodesetval);
12668 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012669 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012670 /* optimizer */
12671 if (total > cur)
12672 xmlXPathCompSwap(op);
12673 return (total + cur);
12674 case XPATH_OP_ROOT:
12675 xmlXPathRoot(ctxt);
12676 return (0);
12677 case XPATH_OP_NODE:
12678 if (op->ch1 != -1)
12679 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012680 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012681 if (op->ch2 != -1)
12682 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012683 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012684 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12685 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012686 return (total);
12687 case XPATH_OP_RESET:
12688 if (op->ch1 != -1)
12689 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012690 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012691 if (op->ch2 != -1)
12692 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012693 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012694 ctxt->context->node = NULL;
12695 return (total);
12696 case XPATH_OP_COLLECT:{
12697 if (op->ch1 == -1)
12698 return (0);
12699
12700 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012701 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012702
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012703 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012704 return (total);
12705 }
12706 case XPATH_OP_VALUE:
12707 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012708 xmlXPathCacheObjectCopy(ctxt->context,
12709 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012710 return (0);
12711 case XPATH_OP_SORT:
12712 if (op->ch1 != -1)
12713 total +=
12714 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12715 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012716 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012717 if ((ctxt->value != NULL)
12718 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012719 && (ctxt->value->nodesetval != NULL)
12720 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012721 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12722 return (total);
12723 default:
12724 return (xmlXPathCompOpEval(ctxt, op));
12725 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012726}
12727
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012728#ifdef XP_OPTIMIZED_FILTER_FIRST
12729static int
12730xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12731 xmlXPathStepOpPtr op, xmlNodePtr * first)
12732{
12733 int total = 0;
12734 xmlXPathCompExprPtr comp;
12735 xmlXPathObjectPtr res;
12736 xmlXPathObjectPtr obj;
12737 xmlNodeSetPtr oldset;
12738 xmlNodePtr oldnode;
12739 xmlDocPtr oldDoc;
12740 int i;
12741
12742 CHECK_ERROR0;
12743 comp = ctxt->comp;
12744 /*
12745 * Optimization for ()[last()] selection i.e. the last elem
12746 */
12747 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12748 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12749 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12750 int f = comp->steps[op->ch2].ch1;
12751
12752 if ((f != -1) &&
12753 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12754 (comp->steps[f].value5 == NULL) &&
12755 (comp->steps[f].value == 0) &&
12756 (comp->steps[f].value4 != NULL) &&
12757 (xmlStrEqual
12758 (comp->steps[f].value4, BAD_CAST "last"))) {
12759 xmlNodePtr last = NULL;
12760
12761 total +=
12762 xmlXPathCompOpEvalLast(ctxt,
12763 &comp->steps[op->ch1],
12764 &last);
12765 CHECK_ERROR0;
12766 /*
12767 * The nodeset should be in document order,
12768 * Keep only the last value
12769 */
12770 if ((ctxt->value != NULL) &&
12771 (ctxt->value->type == XPATH_NODESET) &&
12772 (ctxt->value->nodesetval != NULL) &&
12773 (ctxt->value->nodesetval->nodeTab != NULL) &&
12774 (ctxt->value->nodesetval->nodeNr > 1)) {
12775 ctxt->value->nodesetval->nodeTab[0] =
12776 ctxt->value->nodesetval->nodeTab[ctxt->
12777 value->
12778 nodesetval->
12779 nodeNr -
12780 1];
12781 ctxt->value->nodesetval->nodeNr = 1;
12782 *first = *(ctxt->value->nodesetval->nodeTab);
12783 }
12784 return (total);
12785 }
12786 }
12787
12788 if (op->ch1 != -1)
12789 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12790 CHECK_ERROR0;
12791 if (op->ch2 == -1)
12792 return (total);
12793 if (ctxt->value == NULL)
12794 return (total);
12795
12796#ifdef LIBXML_XPTR_ENABLED
12797 oldnode = ctxt->context->node;
12798 /*
12799 * Hum are we filtering the result of an XPointer expression
12800 */
12801 if (ctxt->value->type == XPATH_LOCATIONSET) {
12802 xmlXPathObjectPtr tmp = NULL;
12803 xmlLocationSetPtr newlocset = NULL;
12804 xmlLocationSetPtr oldlocset;
12805
12806 /*
12807 * Extract the old locset, and then evaluate the result of the
12808 * expression for all the element in the locset. use it to grow
12809 * up a new locset.
12810 */
12811 CHECK_TYPE0(XPATH_LOCATIONSET);
12812 obj = valuePop(ctxt);
12813 oldlocset = obj->user;
12814 ctxt->context->node = NULL;
12815
12816 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12817 ctxt->context->contextSize = 0;
12818 ctxt->context->proximityPosition = 0;
12819 if (op->ch2 != -1)
12820 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12821 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012822 if (res != NULL) {
12823 xmlXPathReleaseObject(ctxt->context, res);
12824 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012825 valuePush(ctxt, obj);
12826 CHECK_ERROR0;
12827 return (total);
12828 }
12829 newlocset = xmlXPtrLocationSetCreate(NULL);
12830
12831 for (i = 0; i < oldlocset->locNr; i++) {
12832 /*
12833 * Run the evaluation with a node list made of a
12834 * single item in the nodelocset.
12835 */
12836 ctxt->context->node = oldlocset->locTab[i]->user;
12837 ctxt->context->contextSize = oldlocset->locNr;
12838 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012839 if (tmp == NULL) {
12840 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12841 ctxt->context->node);
12842 } else {
12843 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12844 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012845 }
12846 valuePush(ctxt, tmp);
12847 if (op->ch2 != -1)
12848 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12849 if (ctxt->error != XPATH_EXPRESSION_OK) {
12850 xmlXPathFreeObject(obj);
12851 return(0);
12852 }
12853 /*
12854 * The result of the evaluation need to be tested to
12855 * decided whether the filter succeeded or not
12856 */
12857 res = valuePop(ctxt);
12858 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12859 xmlXPtrLocationSetAdd(newlocset,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012860 xmlXPathCacheObjectCopy(ctxt->context,
12861 oldlocset->locTab[i]));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012862 }
12863 /*
12864 * Cleanup
12865 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012866 if (res != NULL) {
12867 xmlXPathReleaseObject(ctxt->context, res);
12868 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012869 if (ctxt->value == tmp) {
12870 valuePop(ctxt);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012871 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012872 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012873 * REVISIT TODO: Don't create a temporary nodeset
12874 * for everly iteration.
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012875 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012876 /* OLD: xmlXPathFreeObject(res); */
12877 } else
12878 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012879 ctxt->context->node = NULL;
12880 /*
12881 * Only put the first node in the result, then leave.
12882 */
12883 if (newlocset->locNr > 0) {
12884 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
12885 break;
12886 }
12887 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012888 if (tmp != NULL) {
12889 xmlXPathReleaseObject(ctxt->context, tmp);
12890 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012891 /*
12892 * The result is used as the new evaluation locset.
12893 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012894 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012895 ctxt->context->node = NULL;
12896 ctxt->context->contextSize = -1;
12897 ctxt->context->proximityPosition = -1;
12898 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12899 ctxt->context->node = oldnode;
12900 return (total);
12901 }
12902#endif /* LIBXML_XPTR_ENABLED */
12903
12904 /*
12905 * Extract the old set, and then evaluate the result of the
12906 * expression for all the element in the set. use it to grow
12907 * up a new set.
12908 */
12909 CHECK_TYPE0(XPATH_NODESET);
12910 obj = valuePop(ctxt);
12911 oldset = obj->nodesetval;
12912
12913 oldnode = ctxt->context->node;
12914 oldDoc = ctxt->context->doc;
12915 ctxt->context->node = NULL;
12916
12917 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
12918 ctxt->context->contextSize = 0;
12919 ctxt->context->proximityPosition = 0;
12920 /* QUESTION TODO: Why was this code commented out?
12921 if (op->ch2 != -1)
12922 total +=
12923 xmlXPathCompOpEval(ctxt,
12924 &comp->steps[op->ch2]);
12925 CHECK_ERROR0;
12926 res = valuePop(ctxt);
12927 if (res != NULL)
12928 xmlXPathFreeObject(res);
12929 */
12930 valuePush(ctxt, obj);
12931 ctxt->context->node = oldnode;
12932 CHECK_ERROR0;
12933 } else {
12934 xmlNodeSetPtr newset;
12935 xmlXPathObjectPtr tmp = NULL;
12936 /*
12937 * Initialize the new set.
12938 * Also set the xpath document in case things like
12939 * key() evaluation are attempted on the predicate
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012940 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012941 newset = xmlXPathNodeSetCreate(NULL);
12942
12943 for (i = 0; i < oldset->nodeNr; i++) {
12944 /*
12945 * Run the evaluation with a node list made of
12946 * a single item in the nodeset.
12947 */
12948 ctxt->context->node = oldset->nodeTab[i];
12949 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
12950 (oldset->nodeTab[i]->doc != NULL))
12951 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012952 if (tmp == NULL) {
12953 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12954 ctxt->context->node);
12955 } else {
12956 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12957 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012958 }
12959 valuePush(ctxt, tmp);
12960 ctxt->context->contextSize = oldset->nodeNr;
12961 ctxt->context->proximityPosition = i + 1;
12962 if (op->ch2 != -1)
12963 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12964 if (ctxt->error != XPATH_EXPRESSION_OK) {
12965 xmlXPathFreeNodeSet(newset);
12966 xmlXPathFreeObject(obj);
12967 return(0);
12968 }
12969 /*
12970 * The result of the evaluation needs to be tested to
12971 * decide whether the filter succeeded or not
12972 */
12973 res = valuePop(ctxt);
12974 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12975 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
12976 }
12977 /*
12978 * Cleanup
12979 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012980 if (res != NULL) {
12981 xmlXPathReleaseObject(ctxt->context, res);
12982 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012983 if (ctxt->value == tmp) {
12984 valuePop(ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012985 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012986 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012987 * in order to avoid massive recreation inside this
12988 * loop.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012989 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012990 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012991 } else
12992 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012993 ctxt->context->node = NULL;
12994 /*
12995 * Only put the first node in the result, then leave.
12996 */
12997 if (newset->nodeNr > 0) {
12998 *first = *(newset->nodeTab);
12999 break;
13000 }
13001 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013002 if (tmp != NULL) {
13003 xmlXPathReleaseObject(ctxt->context, tmp);
13004 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013005 /*
13006 * The result is used as the new evaluation set.
13007 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013008 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013009 ctxt->context->node = NULL;
13010 ctxt->context->contextSize = -1;
13011 ctxt->context->proximityPosition = -1;
13012 /* may want to move this past the '}' later */
13013 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013014 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013015 }
13016 ctxt->context->node = oldnode;
13017 return(total);
13018}
13019#endif /* XP_OPTIMIZED_FILTER_FIRST */
13020
Owen Taylor3473f882001-02-23 17:55:21 +000013021/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013022 * xmlXPathCompOpEval:
13023 * @ctxt: the XPath parser context with the compiled expression
13024 * @op: an XPath compiled operation
13025 *
13026 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000013027 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013028 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013029static int
13030xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13031{
13032 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013033 int equal, ret;
13034 xmlXPathCompExprPtr comp;
13035 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013036 xmlNodePtr bak;
13037 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000013038 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000013039 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013040
Daniel Veillard556c6682001-10-06 09:59:51 +000013041 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013042 comp = ctxt->comp;
13043 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013044 case XPATH_OP_END:
13045 return (0);
13046 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013047 bakd = ctxt->context->doc;
13048 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013049 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013050 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013051 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013052 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013053 xmlXPathBooleanFunction(ctxt, 1);
13054 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13055 return (total);
13056 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013057 ctxt->context->doc = bakd;
13058 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013059 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013060 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013061 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013062 if (ctxt->error) {
13063 xmlXPathFreeObject(arg2);
13064 return(0);
13065 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013066 xmlXPathBooleanFunction(ctxt, 1);
13067 arg1 = valuePop(ctxt);
13068 arg1->boolval &= arg2->boolval;
13069 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013070 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013071 return (total);
13072 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013073 bakd = ctxt->context->doc;
13074 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013075 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013076 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013077 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013078 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013079 xmlXPathBooleanFunction(ctxt, 1);
13080 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13081 return (total);
13082 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013083 ctxt->context->doc = bakd;
13084 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013085 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013086 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013087 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013088 if (ctxt->error) {
13089 xmlXPathFreeObject(arg2);
13090 return(0);
13091 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013092 xmlXPathBooleanFunction(ctxt, 1);
13093 arg1 = valuePop(ctxt);
13094 arg1->boolval |= arg2->boolval;
13095 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013096 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013097 return (total);
13098 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013099 bakd = ctxt->context->doc;
13100 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013101 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013102 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013103 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013104 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013105 ctxt->context->doc = bakd;
13106 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013107 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013108 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013109 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013110 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000013111 if (op->value)
13112 equal = xmlXPathEqualValues(ctxt);
13113 else
13114 equal = xmlXPathNotEqualValues(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013115 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013116 return (total);
13117 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013118 bakd = ctxt->context->doc;
13119 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013120 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013121 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013122 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013123 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013124 ctxt->context->doc = bakd;
13125 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013126 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013127 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013128 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013129 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013130 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013131 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013132 return (total);
13133 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013134 bakd = ctxt->context->doc;
13135 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013136 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013137 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013138 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013139 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013140 if (op->ch2 != -1) {
13141 ctxt->context->doc = bakd;
13142 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013143 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013144 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013145 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013146 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013147 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013148 if (op->value == 0)
13149 xmlXPathSubValues(ctxt);
13150 else if (op->value == 1)
13151 xmlXPathAddValues(ctxt);
13152 else if (op->value == 2)
13153 xmlXPathValueFlipSign(ctxt);
13154 else if (op->value == 3) {
13155 CAST_TO_NUMBER;
13156 CHECK_TYPE0(XPATH_NUMBER);
13157 }
13158 return (total);
13159 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013160 bakd = ctxt->context->doc;
13161 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013162 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013163 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013164 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013165 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013166 ctxt->context->doc = bakd;
13167 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013168 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013169 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013170 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013171 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013172 if (op->value == 0)
13173 xmlXPathMultValues(ctxt);
13174 else if (op->value == 1)
13175 xmlXPathDivValues(ctxt);
13176 else if (op->value == 2)
13177 xmlXPathModValues(ctxt);
13178 return (total);
13179 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013180 bakd = ctxt->context->doc;
13181 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013182 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013183 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013184 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013185 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013186 ctxt->context->doc = bakd;
13187 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013188 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013189 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013190 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013191 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013192 CHECK_TYPE0(XPATH_NODESET);
13193 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013194
Daniel Veillardf06307e2001-07-03 10:35:50 +000013195 CHECK_TYPE0(XPATH_NODESET);
13196 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013197
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013198 if ((arg1->nodesetval == NULL) ||
13199 ((arg2->nodesetval != NULL) &&
13200 (arg2->nodesetval->nodeNr != 0)))
13201 {
13202 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13203 arg2->nodesetval);
13204 }
13205
Daniel Veillardf06307e2001-07-03 10:35:50 +000013206 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013207 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013208 return (total);
13209 case XPATH_OP_ROOT:
13210 xmlXPathRoot(ctxt);
13211 return (total);
13212 case XPATH_OP_NODE:
13213 if (op->ch1 != -1)
13214 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013215 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013216 if (op->ch2 != -1)
13217 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013218 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013219 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13220 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013221 return (total);
13222 case XPATH_OP_RESET:
13223 if (op->ch1 != -1)
13224 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013225 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013226 if (op->ch2 != -1)
13227 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013228 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013229 ctxt->context->node = NULL;
13230 return (total);
13231 case XPATH_OP_COLLECT:{
13232 if (op->ch1 == -1)
13233 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000013234
Daniel Veillardf06307e2001-07-03 10:35:50 +000013235 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013236 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013237
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013238 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013239 return (total);
13240 }
13241 case XPATH_OP_VALUE:
13242 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013243 xmlXPathCacheObjectCopy(ctxt->context,
13244 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013245 return (total);
13246 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000013247 xmlXPathObjectPtr val;
13248
Daniel Veillardf06307e2001-07-03 10:35:50 +000013249 if (op->ch1 != -1)
13250 total +=
13251 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013252 if (op->value5 == NULL) {
13253 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13254 if (val == NULL) {
13255 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13256 return(0);
13257 }
13258 valuePush(ctxt, val);
13259 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013260 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013261
Daniel Veillardf06307e2001-07-03 10:35:50 +000013262 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13263 if (URI == NULL) {
13264 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013265 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000013266 op->value4, op->value5);
13267 return (total);
13268 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013269 val = xmlXPathVariableLookupNS(ctxt->context,
13270 op->value4, URI);
13271 if (val == NULL) {
13272 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13273 return(0);
13274 }
13275 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013276 }
13277 return (total);
13278 }
13279 case XPATH_OP_FUNCTION:{
13280 xmlXPathFunction func;
13281 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000013282 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013283
13284 if (op->ch1 != -1)
13285 total +=
13286 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013287 if (ctxt->valueNr < op->value) {
13288 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013289 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013290 ctxt->error = XPATH_INVALID_OPERAND;
13291 return (total);
13292 }
13293 for (i = 0; i < op->value; i++)
13294 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13295 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013296 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013297 ctxt->error = XPATH_INVALID_OPERAND;
13298 return (total);
13299 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013300 if (op->cache != NULL)
William M. Brackad0e67c2004-12-01 14:35:10 +000013301 XML_CAST_FPTR(func) = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013302 else {
13303 const xmlChar *URI = NULL;
13304
13305 if (op->value5 == NULL)
13306 func =
13307 xmlXPathFunctionLookup(ctxt->context,
13308 op->value4);
13309 else {
13310 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13311 if (URI == NULL) {
13312 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013313 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000013314 op->value4, op->value5);
13315 return (total);
13316 }
13317 func = xmlXPathFunctionLookupNS(ctxt->context,
13318 op->value4, URI);
13319 }
13320 if (func == NULL) {
13321 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013322 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000013323 op->value4);
13324 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013325 }
William M. Brackad0e67c2004-12-01 14:35:10 +000013326 op->cache = XML_CAST_FPTR(func);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013327 op->cacheURI = (void *) URI;
13328 }
13329 oldFunc = ctxt->context->function;
13330 oldFuncURI = ctxt->context->functionURI;
13331 ctxt->context->function = op->value4;
13332 ctxt->context->functionURI = op->cacheURI;
13333 func(ctxt, op->value);
13334 ctxt->context->function = oldFunc;
13335 ctxt->context->functionURI = oldFuncURI;
13336 return (total);
13337 }
13338 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000013339 bakd = ctxt->context->doc;
13340 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000013341 pp = ctxt->context->proximityPosition;
13342 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013343 if (op->ch1 != -1)
13344 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
William M. Brack645a9242004-11-09 12:20:42 +000013345 ctxt->context->contextSize = cs;
13346 ctxt->context->proximityPosition = pp;
Daniel Veillard088bf112002-05-14 11:03:59 +000013347 ctxt->context->node = bak;
William M. Brack645a9242004-11-09 12:20:42 +000013348 ctxt->context->doc = bakd;
Daniel Veillard556c6682001-10-06 09:59:51 +000013349 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000013350 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013351 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000013352 ctxt->context->doc = bakd;
13353 ctxt->context->node = bak;
13354 CHECK_ERROR0;
13355 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013356 return (total);
13357 case XPATH_OP_PREDICATE:
13358 case XPATH_OP_FILTER:{
13359 xmlXPathObjectPtr res;
13360 xmlXPathObjectPtr obj, tmp;
13361 xmlNodeSetPtr newset = NULL;
13362 xmlNodeSetPtr oldset;
13363 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000013364 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013365 int i;
13366
13367 /*
13368 * Optimization for ()[1] selection i.e. the first elem
13369 */
13370 if ((op->ch1 != -1) && (op->ch2 != -1) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013371#ifdef XP_OPTIMIZED_FILTER_FIRST
13372 /*
13373 * FILTER TODO: Can we assume that the inner processing
13374 * will result in an ordered list if we have an
13375 * XPATH_OP_FILTER?
13376 * What about an additional field or flag on
13377 * xmlXPathObject like @sorted ? This way we wouln'd need
13378 * to assume anything, so it would be more robust and
13379 * easier to optimize.
13380 */
13381 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13382 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13383#else
13384 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13385#endif
13386 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013387 xmlXPathObjectPtr val;
13388
13389 val = comp->steps[op->ch2].value4;
13390 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13391 (val->floatval == 1.0)) {
13392 xmlNodePtr first = NULL;
13393
13394 total +=
13395 xmlXPathCompOpEvalFirst(ctxt,
13396 &comp->steps[op->ch1],
13397 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000013398 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013399 /*
13400 * The nodeset should be in document order,
13401 * Keep only the first value
13402 */
13403 if ((ctxt->value != NULL) &&
13404 (ctxt->value->type == XPATH_NODESET) &&
13405 (ctxt->value->nodesetval != NULL) &&
13406 (ctxt->value->nodesetval->nodeNr > 1))
13407 ctxt->value->nodesetval->nodeNr = 1;
13408 return (total);
13409 }
13410 }
13411 /*
13412 * Optimization for ()[last()] selection i.e. the last elem
13413 */
13414 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13415 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13416 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13417 int f = comp->steps[op->ch2].ch1;
13418
13419 if ((f != -1) &&
13420 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13421 (comp->steps[f].value5 == NULL) &&
13422 (comp->steps[f].value == 0) &&
13423 (comp->steps[f].value4 != NULL) &&
13424 (xmlStrEqual
13425 (comp->steps[f].value4, BAD_CAST "last"))) {
13426 xmlNodePtr last = NULL;
13427
13428 total +=
13429 xmlXPathCompOpEvalLast(ctxt,
13430 &comp->steps[op->ch1],
13431 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000013432 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013433 /*
13434 * The nodeset should be in document order,
13435 * Keep only the last value
13436 */
13437 if ((ctxt->value != NULL) &&
13438 (ctxt->value->type == XPATH_NODESET) &&
13439 (ctxt->value->nodesetval != NULL) &&
13440 (ctxt->value->nodesetval->nodeTab != NULL) &&
13441 (ctxt->value->nodesetval->nodeNr > 1)) {
13442 ctxt->value->nodesetval->nodeTab[0] =
13443 ctxt->value->nodesetval->nodeTab[ctxt->
13444 value->
13445 nodesetval->
13446 nodeNr -
13447 1];
13448 ctxt->value->nodesetval->nodeNr = 1;
13449 }
13450 return (total);
13451 }
13452 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013453 /*
13454 * Process inner predicates first.
13455 * Example "index[parent::book][1]":
13456 * ...
13457 * PREDICATE <-- we are here "[1]"
13458 * PREDICATE <-- process "[parent::book]" first
13459 * SORT
13460 * COLLECT 'parent' 'name' 'node' book
13461 * NODE
13462 * ELEM Object is a number : 1
13463 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013464 if (op->ch1 != -1)
13465 total +=
13466 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013467 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013468 if (op->ch2 == -1)
13469 return (total);
13470 if (ctxt->value == NULL)
13471 return (total);
13472
13473 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013474
13475#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013476 /*
13477 * Hum are we filtering the result of an XPointer expression
13478 */
13479 if (ctxt->value->type == XPATH_LOCATIONSET) {
13480 xmlLocationSetPtr newlocset = NULL;
13481 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013482
Daniel Veillardf06307e2001-07-03 10:35:50 +000013483 /*
13484 * Extract the old locset, and then evaluate the result of the
13485 * expression for all the element in the locset. use it to grow
13486 * up a new locset.
13487 */
13488 CHECK_TYPE0(XPATH_LOCATIONSET);
13489 obj = valuePop(ctxt);
13490 oldlocset = obj->user;
13491 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013492
Daniel Veillardf06307e2001-07-03 10:35:50 +000013493 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13494 ctxt->context->contextSize = 0;
13495 ctxt->context->proximityPosition = 0;
13496 if (op->ch2 != -1)
13497 total +=
13498 xmlXPathCompOpEval(ctxt,
13499 &comp->steps[op->ch2]);
13500 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013501 if (res != NULL) {
13502 xmlXPathReleaseObject(ctxt->context, res);
13503 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013504 valuePush(ctxt, obj);
13505 CHECK_ERROR0;
13506 return (total);
13507 }
13508 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013509
Daniel Veillardf06307e2001-07-03 10:35:50 +000013510 for (i = 0; i < oldlocset->locNr; i++) {
13511 /*
13512 * Run the evaluation with a node list made of a
13513 * single item in the nodelocset.
13514 */
13515 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013516 ctxt->context->contextSize = oldlocset->locNr;
13517 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013518 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13519 ctxt->context->node);
William M. Brackf7eb7942003-12-31 07:59:17 +000013520 valuePush(ctxt, tmp);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013521
Daniel Veillardf06307e2001-07-03 10:35:50 +000013522 if (op->ch2 != -1)
13523 total +=
13524 xmlXPathCompOpEval(ctxt,
13525 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013526 if (ctxt->error != XPATH_EXPRESSION_OK) {
13527 xmlXPathFreeObject(obj);
13528 return(0);
13529 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013530
Daniel Veillardf06307e2001-07-03 10:35:50 +000013531 /*
13532 * The result of the evaluation need to be tested to
13533 * decided whether the filter succeeded or not
13534 */
13535 res = valuePop(ctxt);
13536 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13537 xmlXPtrLocationSetAdd(newlocset,
13538 xmlXPathObjectCopy
13539 (oldlocset->locTab[i]));
13540 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013541
Daniel Veillardf06307e2001-07-03 10:35:50 +000013542 /*
13543 * Cleanup
13544 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013545 if (res != NULL) {
13546 xmlXPathReleaseObject(ctxt->context, res);
13547 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013548 if (ctxt->value == tmp) {
13549 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013550 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013551 }
13552
13553 ctxt->context->node = NULL;
13554 }
13555
13556 /*
13557 * The result is used as the new evaluation locset.
13558 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013559 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013560 ctxt->context->node = NULL;
13561 ctxt->context->contextSize = -1;
13562 ctxt->context->proximityPosition = -1;
13563 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13564 ctxt->context->node = oldnode;
13565 return (total);
13566 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013567#endif /* LIBXML_XPTR_ENABLED */
13568
Daniel Veillardf06307e2001-07-03 10:35:50 +000013569 /*
13570 * Extract the old set, and then evaluate the result of the
13571 * expression for all the element in the set. use it to grow
13572 * up a new set.
13573 */
13574 CHECK_TYPE0(XPATH_NODESET);
13575 obj = valuePop(ctxt);
13576 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000013577
Daniel Veillardf06307e2001-07-03 10:35:50 +000013578 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000013579 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013580 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013581
Daniel Veillardf06307e2001-07-03 10:35:50 +000013582 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13583 ctxt->context->contextSize = 0;
13584 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000013585/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000013586 if (op->ch2 != -1)
13587 total +=
13588 xmlXPathCompOpEval(ctxt,
13589 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013590 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013591 res = valuePop(ctxt);
13592 if (res != NULL)
13593 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000013594*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000013595 valuePush(ctxt, obj);
13596 ctxt->context->node = oldnode;
13597 CHECK_ERROR0;
13598 } else {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013599 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013600 /*
13601 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000013602 * Also set the xpath document in case things like
13603 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000013604 */
13605 newset = xmlXPathNodeSetCreate(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013606 /*
13607 * SPEC XPath 1.0:
13608 * "For each node in the node-set to be filtered, the
13609 * PredicateExpr is evaluated with that node as the
13610 * context node, with the number of nodes in the
13611 * node-set as the context size, and with the proximity
13612 * position of the node in the node-set with respect to
13613 * the axis as the context position;"
13614 * @oldset is the node-set" to be filtered.
13615 *
13616 * SPEC XPath 1.0:
13617 * "only predicates change the context position and
13618 * context size (see [2.4 Predicates])."
13619 * Example:
13620 * node-set context pos
13621 * nA 1
13622 * nB 2
13623 * nC 3
13624 * After applying predicate [position() > 1] :
13625 * node-set context pos
13626 * nB 1
13627 * nC 2
13628 *
13629 * removed the first node in the node-set, then
13630 * the context position of the
13631 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013632 for (i = 0; i < oldset->nodeNr; i++) {
13633 /*
13634 * Run the evaluation with a node list made of
13635 * a single item in the nodeset.
13636 */
13637 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000013638 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13639 (oldset->nodeTab[i]->doc != NULL))
13640 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013641 if (tmp == NULL) {
13642 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13643 ctxt->context->node);
13644 } else {
13645 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13646 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013647 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013648 valuePush(ctxt, tmp);
13649 ctxt->context->contextSize = oldset->nodeNr;
13650 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013651 /*
13652 * Evaluate the predicate against the context node.
13653 * Can/should we optimize position() predicates
13654 * here (e.g. "[1]")?
13655 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013656 if (op->ch2 != -1)
13657 total +=
13658 xmlXPathCompOpEval(ctxt,
13659 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013660 if (ctxt->error != XPATH_EXPRESSION_OK) {
13661 xmlXPathFreeNodeSet(newset);
13662 xmlXPathFreeObject(obj);
13663 return(0);
13664 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013665
Daniel Veillardf06307e2001-07-03 10:35:50 +000013666 /*
William M. Brack08171912003-12-29 02:52:11 +000013667 * The result of the evaluation needs to be tested to
13668 * decide whether the filter succeeded or not
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013669 */
13670 /*
13671 * OPTIMIZE TODO: Can we use
13672 * xmlXPathNodeSetAdd*Unique()* instead?
13673 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013674 res = valuePop(ctxt);
13675 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13676 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13677 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013678
Daniel Veillardf06307e2001-07-03 10:35:50 +000013679 /*
13680 * Cleanup
13681 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013682 if (res != NULL) {
13683 xmlXPathReleaseObject(ctxt->context, res);
13684 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013685 if (ctxt->value == tmp) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013686 valuePop(ctxt);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000013687 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013688 /*
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013689 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013690 * in order to avoid massive recreation inside this
13691 * loop.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013692 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013693 } else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013694 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013695 ctxt->context->node = NULL;
13696 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013697 if (tmp != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013698 xmlXPathReleaseObject(ctxt->context, tmp);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013699 /*
13700 * The result is used as the new evaluation set.
13701 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013702 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013703 ctxt->context->node = NULL;
13704 ctxt->context->contextSize = -1;
13705 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000013706 /* may want to move this past the '}' later */
13707 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013708 valuePush(ctxt,
13709 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013710 }
13711 ctxt->context->node = oldnode;
13712 return (total);
13713 }
13714 case XPATH_OP_SORT:
13715 if (op->ch1 != -1)
13716 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013717 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013718 if ((ctxt->value != NULL) &&
13719 (ctxt->value->type == XPATH_NODESET) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013720 (ctxt->value->nodesetval != NULL) &&
13721 (ctxt->value->nodesetval->nodeNr > 1))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013722 {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013723 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013724 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013725 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013726#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013727 case XPATH_OP_RANGETO:{
13728 xmlXPathObjectPtr range;
13729 xmlXPathObjectPtr res, obj;
13730 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000013731 xmlLocationSetPtr newlocset = NULL;
13732 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013733 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000013734 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013735
Daniel Veillardf06307e2001-07-03 10:35:50 +000013736 if (op->ch1 != -1)
13737 total +=
13738 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13739 if (op->ch2 == -1)
13740 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013741
William M. Brack08171912003-12-29 02:52:11 +000013742 if (ctxt->value->type == XPATH_LOCATIONSET) {
13743 /*
13744 * Extract the old locset, and then evaluate the result of the
13745 * expression for all the element in the locset. use it to grow
13746 * up a new locset.
13747 */
13748 CHECK_TYPE0(XPATH_LOCATIONSET);
13749 obj = valuePop(ctxt);
13750 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013751
William M. Brack08171912003-12-29 02:52:11 +000013752 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000013753 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000013754 ctxt->context->contextSize = 0;
13755 ctxt->context->proximityPosition = 0;
13756 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13757 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013758 if (res != NULL) {
13759 xmlXPathReleaseObject(ctxt->context, res);
13760 }
William M. Brack08171912003-12-29 02:52:11 +000013761 valuePush(ctxt, obj);
13762 CHECK_ERROR0;
13763 return (total);
13764 }
13765 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013766
William M. Brack08171912003-12-29 02:52:11 +000013767 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013768 /*
William M. Brack08171912003-12-29 02:52:11 +000013769 * Run the evaluation with a node list made of a
13770 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000013771 */
William M. Brackf7eb7942003-12-31 07:59:17 +000013772 ctxt->context->node = oldlocset->locTab[i]->user;
13773 ctxt->context->contextSize = oldlocset->locNr;
13774 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013775 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13776 ctxt->context->node);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013777 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013778
Daniel Veillardf06307e2001-07-03 10:35:50 +000013779 if (op->ch2 != -1)
13780 total +=
13781 xmlXPathCompOpEval(ctxt,
13782 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013783 if (ctxt->error != XPATH_EXPRESSION_OK) {
13784 xmlXPathFreeObject(obj);
13785 return(0);
13786 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013787
Daniel Veillardf06307e2001-07-03 10:35:50 +000013788 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000013789 if (res->type == XPATH_LOCATIONSET) {
13790 xmlLocationSetPtr rloc =
13791 (xmlLocationSetPtr)res->user;
13792 for (j=0; j<rloc->locNr; j++) {
13793 range = xmlXPtrNewRange(
13794 oldlocset->locTab[i]->user,
13795 oldlocset->locTab[i]->index,
13796 rloc->locTab[j]->user2,
13797 rloc->locTab[j]->index2);
13798 if (range != NULL) {
13799 xmlXPtrLocationSetAdd(newlocset, range);
13800 }
13801 }
13802 } else {
13803 range = xmlXPtrNewRangeNodeObject(
13804 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13805 if (range != NULL) {
13806 xmlXPtrLocationSetAdd(newlocset,range);
13807 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013808 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013809
Daniel Veillardf06307e2001-07-03 10:35:50 +000013810 /*
13811 * Cleanup
13812 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013813 if (res != NULL) {
13814 xmlXPathReleaseObject(ctxt->context, res);
13815 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013816 if (ctxt->value == tmp) {
13817 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013818 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013819 }
13820
13821 ctxt->context->node = NULL;
13822 }
William M. Brack72ee48d2003-12-30 08:30:19 +000013823 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000013824 CHECK_TYPE0(XPATH_NODESET);
13825 obj = valuePop(ctxt);
13826 oldset = obj->nodesetval;
13827 ctxt->context->node = NULL;
13828
13829 newlocset = xmlXPtrLocationSetCreate(NULL);
13830
13831 if (oldset != NULL) {
13832 for (i = 0; i < oldset->nodeNr; i++) {
13833 /*
13834 * Run the evaluation with a node list made of a single item
13835 * in the nodeset.
13836 */
13837 ctxt->context->node = oldset->nodeTab[i];
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013838 /*
13839 * OPTIMIZE TODO: Avoid recreation for every iteration.
13840 */
13841 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13842 ctxt->context->node);
William M. Brack08171912003-12-29 02:52:11 +000013843 valuePush(ctxt, tmp);
13844
13845 if (op->ch2 != -1)
13846 total +=
13847 xmlXPathCompOpEval(ctxt,
13848 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013849 if (ctxt->error != XPATH_EXPRESSION_OK) {
13850 xmlXPathFreeObject(obj);
13851 return(0);
13852 }
William M. Brack08171912003-12-29 02:52:11 +000013853
William M. Brack08171912003-12-29 02:52:11 +000013854 res = valuePop(ctxt);
13855 range =
13856 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13857 res);
13858 if (range != NULL) {
13859 xmlXPtrLocationSetAdd(newlocset, range);
13860 }
13861
13862 /*
13863 * Cleanup
13864 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013865 if (res != NULL) {
13866 xmlXPathReleaseObject(ctxt->context, res);
13867 }
William M. Brack08171912003-12-29 02:52:11 +000013868 if (ctxt->value == tmp) {
13869 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013870 xmlXPathReleaseObject(ctxt->context, res);
William M. Brack08171912003-12-29 02:52:11 +000013871 }
13872
13873 ctxt->context->node = NULL;
13874 }
13875 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013876 }
13877
13878 /*
13879 * The result is used as the new evaluation set.
13880 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013881 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013882 ctxt->context->node = NULL;
13883 ctxt->context->contextSize = -1;
13884 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000013885 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013886 return (total);
13887 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013888#endif /* LIBXML_XPTR_ENABLED */
13889 }
13890 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000013891 "XPath: unknown precompiled operation %d\n", op->op);
13892 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013893}
13894
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013895/**
13896 * xmlXPathCompOpEvalToBoolean:
13897 * @ctxt: the XPath parser context
13898 *
13899 * Evaluates if the expression evaluates to true.
13900 *
13901 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13902 */
13903static int
13904xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13905 xmlXPathStepOpPtr op)
13906{
13907
13908start:
13909 /* comp = ctxt->comp; */
13910 switch (op->op) {
13911 case XPATH_OP_END:
13912 return (0);
13913 case XPATH_OP_VALUE:
13914 if (xmlXPathEvaluatePredicateResult(ctxt,
13915 (xmlXPathObjectPtr) op->value4))
13916 {
13917 return(1);
13918 } else
13919 return(0);
13920 case XPATH_OP_SORT:
13921 /*
13922 * We don't need sorting for boolean results. Skip this one.
13923 */
13924 if (op->ch1 != -1) {
13925 op = &ctxt->comp->steps[op->ch1];
13926 goto start;
13927 }
13928 return(0);
13929 case XPATH_OP_COLLECT: {
13930 xmlXPathObjectPtr resObj;
13931
13932 if (op->ch1 == -1)
13933 return(0);
13934
13935 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13936 if (ctxt->error != XPATH_EXPRESSION_OK)
13937 return(-1);
13938
13939 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13940 if (ctxt->error != XPATH_EXPRESSION_OK)
13941 return(-1);
13942
13943 resObj = valuePop(ctxt);
13944 if (resObj == NULL)
13945 return(-1);
13946
13947 if (xmlXPathEvaluatePredicateResult(ctxt, resObj)) {
13948 xmlXPathReleaseObject(ctxt->context, resObj);
13949 return(1);
13950 } else {
13951 xmlXPathReleaseObject(ctxt->context, resObj);
13952 return(0);
13953 }
13954 }
13955 break;
13956 default: {
13957 xmlXPathObjectPtr resObj;
13958
13959 /*
13960 * Fallback to call xmlXPathCompOpEval().
13961 */
13962 xmlXPathCompOpEval(ctxt, op);
13963 if (ctxt->error != XPATH_EXPRESSION_OK)
13964 return(-1);
13965
13966 resObj = valuePop(ctxt);
13967 if (resObj == NULL)
13968 return(-1);
13969 /*
13970 * This checks if the result of the evaluation is 'true'.
13971 */
13972 if (xmlXPathEvaluatePredicateResult(ctxt, resObj)) {
13973 xmlXPathReleaseObject(ctxt->context, resObj);
13974 return(1);
13975 } else {
13976 xmlXPathReleaseObject(ctxt->context, resObj);
13977 return(0);
13978 }
13979 }
13980 }
13981 return(0);
13982}
13983
Daniel Veillard56de87e2005-02-16 00:22:29 +000013984#ifdef XPATH_STREAMING
13985/**
13986 * xmlXPathRunStreamEval:
13987 * @ctxt: the XPath parser context with the compiled expression
13988 *
13989 * Evaluate the Precompiled Streamable XPath expression in the given context.
13990 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013991static int
13992xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
13993 xmlXPathObjectPtr *resultSeq, int toBool)
13994{
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013995 int max_depth, min_depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013996 int from_root;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013997 int ret, depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013998 int eval_all_nodes;
William M. Brack12d37ab2005-02-21 13:54:07 +000013999 xmlNodePtr cur = NULL, limit = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014000 xmlStreamCtxtPtr patstream;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014001
14002 int nb_nodes = 0;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014003
14004 if ((ctxt == NULL) || (comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014005 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014006 max_depth = xmlPatternMaxDepth(comp);
14007 if (max_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014008 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014009 if (max_depth == -2)
14010 max_depth = 10000;
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014011 min_depth = xmlPatternMinDepth(comp);
14012 if (min_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014013 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014014 from_root = xmlPatternFromRoot(comp);
14015 if (from_root < 0)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014016 return(-1);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014017#if 0
14018 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14019#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000014020
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014021 if (! toBool) {
14022 if (resultSeq == NULL)
14023 return(-1);
14024 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14025 if (*resultSeq == NULL)
14026 return(-1);
14027 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014028
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014029 /*
14030 * handle the special cases of / amd . being matched
14031 */
14032 if (min_depth == 0) {
14033 if (from_root) {
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. Buchcik631ea812006-06-26 16:47:25 +000014039 if (toBool)
14040 return(1);
14041 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014042 }
14043 }
14044 if (max_depth == 0) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014045 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014046 }
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014047
Daniel Veillard56de87e2005-02-16 00:22:29 +000014048 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000014049 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014050 } else if (ctxt->node != NULL) {
14051 switch (ctxt->node->type) {
14052 case XML_ELEMENT_NODE:
14053 case XML_DOCUMENT_NODE:
14054 case XML_DOCUMENT_FRAG_NODE:
14055 case XML_HTML_DOCUMENT_NODE:
14056#ifdef LIBXML_DOCB_ENABLED
14057 case XML_DOCB_DOCUMENT_NODE:
14058#endif
14059 cur = ctxt->node;
14060 break;
14061 case XML_ATTRIBUTE_NODE:
14062 case XML_TEXT_NODE:
14063 case XML_CDATA_SECTION_NODE:
14064 case XML_ENTITY_REF_NODE:
14065 case XML_ENTITY_NODE:
14066 case XML_PI_NODE:
14067 case XML_COMMENT_NODE:
14068 case XML_NOTATION_NODE:
14069 case XML_DTD_NODE:
14070 case XML_DOCUMENT_TYPE_NODE:
14071 case XML_ELEMENT_DECL:
14072 case XML_ATTRIBUTE_DECL:
14073 case XML_ENTITY_DECL:
14074 case XML_NAMESPACE_DECL:
14075 case XML_XINCLUDE_START:
14076 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000014077 break;
14078 }
14079 limit = cur;
14080 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014081 if (cur == NULL) {
14082 return(0);
14083 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014084
14085 patstream = xmlPatternGetStreamCtxt(comp);
14086 if (patstream == NULL) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014087 /*
14088 * QUESTION TODO: Is this an error?
14089 */
14090 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014091 }
14092
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014093 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014094
Daniel Veillard56de87e2005-02-16 00:22:29 +000014095 if (from_root) {
14096 ret = xmlStreamPush(patstream, NULL, NULL);
14097 if (ret < 0) {
14098 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014099 if (toBool)
14100 return(1);
14101 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014102 }
14103 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014104 depth = 0;
14105 goto scan_children;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014106next_node:
Daniel Veillardd3ff7ef2006-02-27 19:43:17 +000014107 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014108 nb_nodes++;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014109
14110 switch (cur->type) {
14111 case XML_ELEMENT_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014112 case XML_TEXT_NODE:
14113 case XML_CDATA_SECTION_NODE:
14114 case XML_COMMENT_NODE:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014115 case XML_PI_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014116 if (cur->type == XML_ELEMENT_NODE) {
14117 ret = xmlStreamPush(patstream, cur->name,
Daniel Veillard56de87e2005-02-16 00:22:29 +000014118 (cur->ns ? cur->ns->href : NULL));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014119 } else if (eval_all_nodes)
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014120 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14121 else
14122 break;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014123
14124 if (ret < 0) {
14125 /* NOP. */
14126 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014127 if (toBool)
14128 return(1);
14129 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014130 }
14131 if ((cur->children == NULL) || (depth >= max_depth)) {
14132 ret = xmlStreamPop(patstream);
14133 while (cur->next != NULL) {
14134 cur = cur->next;
14135 if ((cur->type != XML_ENTITY_DECL) &&
14136 (cur->type != XML_DTD_NODE))
14137 goto next_node;
14138 }
14139 }
14140 default:
14141 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014142 }
14143
Daniel Veillard56de87e2005-02-16 00:22:29 +000014144scan_children:
14145 if ((cur->children != NULL) && (depth < max_depth)) {
14146 /*
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014147 * Do not descend on entities declarations
Daniel Veillard56de87e2005-02-16 00:22:29 +000014148 */
14149 if (cur->children->type != XML_ENTITY_DECL) {
14150 cur = cur->children;
14151 depth++;
14152 /*
14153 * Skip DTDs
14154 */
14155 if (cur->type != XML_DTD_NODE)
14156 continue;
14157 }
14158 }
14159
14160 if (cur == limit)
14161 break;
14162
14163 while (cur->next != NULL) {
14164 cur = cur->next;
14165 if ((cur->type != XML_ENTITY_DECL) &&
14166 (cur->type != XML_DTD_NODE))
14167 goto next_node;
14168 }
14169
14170 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014171 cur = cur->parent;
14172 depth--;
14173 if ((cur == NULL) || (cur == limit))
14174 goto done;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014175 if (cur->type == XML_ELEMENT_NODE) {
14176 ret = xmlStreamPop(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014177 } else if ((eval_all_nodes) &&
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014178 ((cur->type == XML_TEXT_NODE) ||
14179 (cur->type == XML_CDATA_SECTION_NODE) ||
14180 (cur->type == XML_COMMENT_NODE) ||
14181 (cur->type == XML_PI_NODE)))
14182 {
14183 ret = xmlStreamPop(patstream);
14184 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014185 if (cur->next != NULL) {
14186 cur = cur->next;
14187 break;
14188 }
14189 } while (cur != NULL);
14190
14191 } while ((cur != NULL) && (depth >= 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014192
Daniel Veillard56de87e2005-02-16 00:22:29 +000014193done:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014194
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014195#if 0
14196 printf("stream eval: checked %d nodes selected %d\n",
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014197 nb_nodes, retObj->nodesetval->nodeNr);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014198#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014199
Daniel Veillard56de87e2005-02-16 00:22:29 +000014200 xmlFreeStreamCtxt(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014201 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014202}
14203#endif /* XPATH_STREAMING */
14204
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014205/**
14206 * xmlXPathRunEval:
14207 * @ctxt: the XPath parser context with the compiled expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014208 * @toBool: evaluate to a boolean result
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014209 *
14210 * Evaluate the Precompiled XPath expression in the given context.
14211 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014212static int
14213xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14214{
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014215 xmlXPathCompExprPtr comp;
14216
14217 if ((ctxt == NULL) || (ctxt->comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014218 return(-1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014219
14220 if (ctxt->valueTab == NULL) {
14221 /* Allocate the value stack */
14222 ctxt->valueTab = (xmlXPathObjectPtr *)
14223 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14224 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000014225 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014226 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014227 }
14228 ctxt->valueNr = 0;
14229 ctxt->valueMax = 10;
14230 ctxt->value = NULL;
14231 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014232#ifdef XPATH_STREAMING
14233 if (ctxt->comp->stream) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014234 int res;
14235
14236 if (toBool) {
14237 /*
14238 * Evaluation to boolean result.
14239 */
14240 res = xmlXPathRunStreamEval(ctxt->context,
14241 ctxt->comp->stream, NULL, 1);
14242 if (res != -1)
14243 return(res);
14244 } else {
14245 xmlXPathObjectPtr resObj = NULL;
14246
14247 /*
14248 * Evaluation to a sequence.
14249 */
14250 res = xmlXPathRunStreamEval(ctxt->context,
14251 ctxt->comp->stream, &resObj, 0);
14252
14253 if ((res != -1) && (resObj != NULL)) {
14254 valuePush(ctxt, resObj);
14255 return(0);
14256 }
14257 if (resObj != NULL)
14258 xmlXPathReleaseObject(ctxt->context, resObj);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014259 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014260 /*
14261 * QUESTION TODO: This falls back to normal XPath evaluation
14262 * if res == -1. Is this intended?
14263 */
Daniel Veillard56de87e2005-02-16 00:22:29 +000014264 }
14265#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014266 comp = ctxt->comp;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014267 if (comp->last < 0) {
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014268 xmlGenericError(xmlGenericErrorContext,
14269 "xmlXPathRunEval: last is less than zero\n");
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014270 return(-1);
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014271 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014272 if (toBool)
14273 return(xmlXPathCompOpEvalToBoolean(ctxt, &comp->steps[comp->last]));
14274 else
14275 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14276
14277 return(0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014278}
14279
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014280/************************************************************************
14281 * *
14282 * Public interfaces *
14283 * *
14284 ************************************************************************/
14285
14286/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014287 * xmlXPathEvalPredicate:
14288 * @ctxt: the XPath context
14289 * @res: the Predicate Expression evaluation result
14290 *
14291 * Evaluate a predicate result for the current node.
14292 * A PredicateExpr is evaluated by evaluating the Expr and converting
14293 * the result to a boolean. If the result is a number, the result will
14294 * be converted to true if the number is equal to the position of the
14295 * context node in the context node list (as returned by the position
14296 * function) and will be converted to false otherwise; if the result
14297 * is not a number, then the result will be converted as if by a call
14298 * to the boolean function.
14299 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014300 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014301 */
14302int
14303xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014304 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014305 switch (res->type) {
14306 case XPATH_BOOLEAN:
14307 return(res->boolval);
14308 case XPATH_NUMBER:
14309 return(res->floatval == ctxt->proximityPosition);
14310 case XPATH_NODESET:
14311 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000014312 if (res->nodesetval == NULL)
14313 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014314 return(res->nodesetval->nodeNr != 0);
14315 case XPATH_STRING:
14316 return((res->stringval != NULL) &&
14317 (xmlStrlen(res->stringval) != 0));
14318 default:
14319 STRANGE
14320 }
14321 return(0);
14322}
14323
14324/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014325 * xmlXPathEvaluatePredicateResult:
14326 * @ctxt: the XPath Parser context
14327 * @res: the Predicate Expression evaluation result
14328 *
14329 * Evaluate a predicate result for the current node.
14330 * A PredicateExpr is evaluated by evaluating the Expr and converting
14331 * the result to a boolean. If the result is a number, the result will
14332 * be converted to true if the number is equal to the position of the
14333 * context node in the context node list (as returned by the position
14334 * function) and will be converted to false otherwise; if the result
14335 * is not a number, then the result will be converted as if by a call
14336 * to the boolean function.
14337 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014338 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014339 */
14340int
14341xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14342 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014343 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014344 switch (res->type) {
14345 case XPATH_BOOLEAN:
14346 return(res->boolval);
14347 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000014348#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000014349 return((res->floatval == ctxt->context->proximityPosition) &&
14350 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000014351#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014352 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000014353#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014354 case XPATH_NODESET:
14355 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000014356 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000014357 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014358 return(res->nodesetval->nodeNr != 0);
14359 case XPATH_STRING:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014360 return((res->stringval != NULL) && (res->stringval[0] != 0));
William M. Brack08171912003-12-29 02:52:11 +000014361#ifdef LIBXML_XPTR_ENABLED
14362 case XPATH_LOCATIONSET:{
14363 xmlLocationSetPtr ptr = res->user;
14364 if (ptr == NULL)
14365 return(0);
14366 return (ptr->locNr != 0);
14367 }
14368#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014369 default:
14370 STRANGE
14371 }
14372 return(0);
14373}
14374
Daniel Veillard56de87e2005-02-16 00:22:29 +000014375#ifdef XPATH_STREAMING
14376/**
14377 * xmlXPathTryStreamCompile:
14378 * @ctxt: an XPath context
14379 * @str: the XPath expression
14380 *
14381 * Try to compile the XPath expression as a streamable subset.
14382 *
14383 * Returns the compiled expression or NULL if failed to compile.
14384 */
14385static xmlXPathCompExprPtr
14386xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14387 /*
14388 * Optimization: use streaming patterns when the XPath expression can
14389 * be compiled to a stream lookup
14390 */
14391 xmlPatternPtr stream;
14392 xmlXPathCompExprPtr comp;
14393 xmlDictPtr dict = NULL;
14394 const xmlChar **namespaces = NULL;
14395 xmlNsPtr ns;
14396 int i, j;
14397
14398 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14399 (!xmlStrchr(str, '@'))) {
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014400 const xmlChar *tmp;
14401
14402 /*
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014403 * We don't try to handle expressions using the verbose axis
14404 * specifiers ("::"), just the simplied form at this point.
14405 * Additionally, if there is no list of namespaces available and
14406 * there's a ":" in the expression, indicating a prefixed QName,
14407 * then we won't try to compile either. xmlPatterncompile() needs
14408 * to have a list of namespaces at compilation time in order to
14409 * compile prefixed name tests.
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014410 */
14411 tmp = xmlStrchr(str, ':');
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014412 if ((tmp != NULL) &&
14413 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14414 return(NULL);
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014415
Daniel Veillard56de87e2005-02-16 00:22:29 +000014416 if (ctxt != NULL) {
14417 dict = ctxt->dict;
14418 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000014419 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000014420 if (namespaces == NULL) {
14421 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14422 return(NULL);
14423 }
14424 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14425 ns = ctxt->namespaces[j];
14426 namespaces[i++] = ns->href;
14427 namespaces[i++] = ns->prefix;
14428 }
14429 namespaces[i++] = NULL;
14430 namespaces[i++] = NULL;
14431 }
14432 }
14433
William M. Brackea152c02005-06-09 18:12:28 +000014434 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14435 &namespaces[0]);
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014436 if (namespaces != NULL) {
14437 xmlFree((xmlChar **)namespaces);
14438 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014439 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14440 comp = xmlXPathNewCompExpr();
14441 if (comp == NULL) {
14442 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14443 return(NULL);
14444 }
14445 comp->stream = stream;
14446 comp->dict = dict;
14447 if (comp->dict)
14448 xmlDictReference(comp->dict);
14449 return(comp);
14450 }
14451 xmlFreePattern(stream);
14452 }
14453 return(NULL);
14454}
14455#endif /* XPATH_STREAMING */
14456
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014457static int
14458xmlXPathCanRewriteDosExpression(xmlChar *expr)
14459{
14460 if (expr == NULL)
14461 return(0);
14462 do {
14463 if ((*expr == '/') && (*(++expr) == '/'))
14464 return(1);
14465 } while (*expr++);
14466 return(0);
14467}
14468static void
14469xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14470{
14471 /*
14472 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14473 * internal representation.
14474 */
14475 if (op->ch1 != -1) {
14476 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14477 ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
14478 ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
14479 ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
14480 {
14481 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014482 * This is a "child::foo"
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014483 */
14484 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14485
14486 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14487 (prevop->ch1 != -1) &&
14488 ((xmlXPathAxisVal) prevop->value ==
14489 AXIS_DESCENDANT_OR_SELF) &&
14490 (prevop->ch2 == -1) &&
14491 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014492 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
14493 (comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014494 {
14495 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014496 * This is a "/descendant-or-self::node()" without predicates.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014497 * Eliminate it.
14498 */
14499 op->ch1 = prevop->ch1;
14500 op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
14501 }
14502 }
14503 if (op->ch1 != -1)
14504 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
14505 }
14506 if (op->ch2 != -1)
14507 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
14508}
14509
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014510/**
Daniel Veillard4773df22004-01-23 13:15:13 +000014511 * xmlXPathCtxtCompile:
14512 * @ctxt: an XPath context
14513 * @str: the XPath expression
14514 *
14515 * Compile an XPath expression
14516 *
14517 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14518 * the caller has to free the object.
14519 */
14520xmlXPathCompExprPtr
14521xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14522 xmlXPathParserContextPtr pctxt;
14523 xmlXPathCompExprPtr comp;
14524
Daniel Veillard56de87e2005-02-16 00:22:29 +000014525#ifdef XPATH_STREAMING
14526 comp = xmlXPathTryStreamCompile(ctxt, str);
14527 if (comp != NULL)
14528 return(comp);
14529#endif
14530
Daniel Veillard4773df22004-01-23 13:15:13 +000014531 xmlXPathInit();
14532
14533 pctxt = xmlXPathNewParserContext(str, ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014534 xmlXPathCompileExpr(pctxt, 1);
Daniel Veillard4773df22004-01-23 13:15:13 +000014535
14536 if( pctxt->error != XPATH_EXPRESSION_OK )
14537 {
14538 xmlXPathFreeParserContext(pctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000014539 return(NULL);
Daniel Veillard4773df22004-01-23 13:15:13 +000014540 }
14541
14542 if (*pctxt->cur != 0) {
14543 /*
14544 * aleksey: in some cases this line prints *second* error message
14545 * (see bug #78858) and probably this should be fixed.
14546 * However, we are not sure that all error messages are printed
14547 * out in other places. It's not critical so we leave it as-is for now
14548 */
14549 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14550 comp = NULL;
14551 } else {
14552 comp = pctxt->comp;
14553 pctxt->comp = NULL;
14554 }
14555 xmlXPathFreeParserContext(pctxt);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014556
Daniel Veillard4773df22004-01-23 13:15:13 +000014557 if (comp != NULL) {
14558 comp->expr = xmlStrdup(str);
14559#ifdef DEBUG_EVAL_COUNTS
14560 comp->string = xmlStrdup(str);
14561 comp->nb = 0;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014562#endif
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014563 if ((comp->expr != NULL) &&
14564 (comp->nbStep > 2) &&
14565 (comp->last >= 0) &&
Kasimier T. Buchcik7cb3fa92006-06-06 15:27:46 +000014566 (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
14567 {
14568 xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014569 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014570 }
Daniel Veillard4773df22004-01-23 13:15:13 +000014571 return(comp);
14572}
14573
14574/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014575 * xmlXPathCompile:
14576 * @str: the XPath expression
14577 *
14578 * Compile an XPath expression
14579 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000014580 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014581 * the caller has to free the object.
14582 */
14583xmlXPathCompExprPtr
14584xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000014585 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014586}
14587
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014588/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014589 * xmlXPathCompiledEvalInternal:
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014590 * @comp: the compiled XPath expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014591 * @ctxt: the XPath context
14592 * @resObj: the resulting XPath object or NULL
14593 * @toBool: 1 if only a boolean result is requested
Owen Taylor3473f882001-02-23 17:55:21 +000014594 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014595 * Evaluate the Precompiled XPath expression in the given context.
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014596 * The caller has to free @resObj.
Owen Taylor3473f882001-02-23 17:55:21 +000014597 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014598 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000014599 * the caller has to free the object.
14600 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014601static int
14602xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14603 xmlXPathContextPtr ctxt,
14604 xmlXPathObjectPtr *resObj,
14605 int toBool)
14606{
14607 xmlXPathParserContextPtr pctxt;
Daniel Veillard81463942001-10-16 12:34:39 +000014608#ifndef LIBXML_THREAD_ENABLED
14609 static int reentance = 0;
14610#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014611 int res;
Owen Taylor3473f882001-02-23 17:55:21 +000014612
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014613 CHECK_CTXT_NEG(ctxt)
William M. Brackf13f77f2004-11-12 16:03:48 +000014614
14615 if (comp == NULL)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014616 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +000014617 xmlXPathInit();
14618
Daniel Veillard81463942001-10-16 12:34:39 +000014619#ifndef LIBXML_THREAD_ENABLED
14620 reentance++;
14621 if (reentance > 1)
14622 xmlXPathDisableOptimizer = 1;
14623#endif
14624
Daniel Veillardf06307e2001-07-03 10:35:50 +000014625#ifdef DEBUG_EVAL_COUNTS
14626 comp->nb++;
14627 if ((comp->string != NULL) && (comp->nb > 100)) {
14628 fprintf(stderr, "100 x %s\n", comp->string);
14629 comp->nb = 0;
14630 }
14631#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014632 pctxt = xmlXPathCompParserContext(comp, ctxt);
14633 res = xmlXPathRunEval(pctxt, toBool);
Owen Taylor3473f882001-02-23 17:55:21 +000014634
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014635 if (resObj) {
14636 if (pctxt->value == NULL) {
14637 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014638 "xmlXPathCompiledEval: evaluation failed\n");
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014639 *resObj = NULL;
14640 } else {
14641 *resObj = valuePop(pctxt);
14642 }
Owen Taylor3473f882001-02-23 17:55:21 +000014643 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014644
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014645 /*
14646 * Pop all remaining objects from the stack.
14647 */
14648 if (pctxt->valueNr > 0) {
14649 xmlXPathObjectPtr tmp;
14650 int stack = 0;
14651
14652 do {
14653 tmp = valuePop(pctxt);
14654 if (tmp != NULL) {
14655 if (tmp != NULL)
14656 stack++;
14657 xmlXPathReleaseObject(ctxt, tmp);
14658 }
14659 } while (tmp != NULL);
14660 if ((stack != 0) &&
14661 ((toBool) || ((resObj) && (*resObj))))
14662 {
14663 xmlGenericError(xmlGenericErrorContext,
14664 "xmlXPathCompiledEval: %d objects left on the stack.\n",
14665 stack);
14666 }
Owen Taylor3473f882001-02-23 17:55:21 +000014667 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014668
14669 if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14670 xmlXPathFreeObject(*resObj);
14671 *resObj = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014672 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014673 pctxt->comp = NULL;
14674 xmlXPathFreeParserContext(pctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000014675#ifndef LIBXML_THREAD_ENABLED
14676 reentance--;
14677#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014678
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014679 return(res);
14680}
14681
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014682/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014683 * xmlXPathCompiledEval:
14684 * @comp: the compiled XPath expression
14685 * @ctx: the XPath context
14686 *
14687 * Evaluate the Precompiled XPath expression in the given context.
14688 *
14689 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14690 * the caller has to free the object.
14691 */
14692xmlXPathObjectPtr
14693xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14694{
14695 xmlXPathObjectPtr res = NULL;
14696
14697 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14698 return(res);
14699}
14700
14701/**
14702 * xmlXPathCompiledEvalToBoolean:
14703 * @comp: the compiled XPath expression
14704 * @ctxt: the XPath context
14705 *
14706 * Applies the XPath boolean() function on the result of the given
14707 * compiled expression.
14708 *
14709 * Returns 1 if the expression evaluated to true, 0 if to false and
14710 * -1 in API and internal errors.
14711 */
14712int
14713xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14714 xmlXPathContextPtr ctxt)
14715{
14716 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14717}
14718
14719/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014720 * xmlXPathEvalExpr:
14721 * @ctxt: the XPath Parser context
14722 *
14723 * Parse and evaluate an XPath expression in the given context,
14724 * then push the result on the context stack
14725 */
14726void
14727xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014728#ifdef XPATH_STREAMING
14729 xmlXPathCompExprPtr comp;
14730#endif
14731
Daniel Veillarda82b1822004-11-08 16:24:57 +000014732 if (ctxt == NULL) return;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014733
14734#ifdef XPATH_STREAMING
14735 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14736 if (comp != NULL) {
14737 if (ctxt->comp != NULL)
14738 xmlXPathFreeCompExpr(ctxt->comp);
14739 ctxt->comp = comp;
14740 if (ctxt->cur != NULL)
14741 while (*ctxt->cur != 0) ctxt->cur++;
14742 } else
14743#endif
14744 {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014745 xmlXPathCompileExpr(ctxt, 1);
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014746 /*
14747 * In this scenario the expression string will sit in ctxt->base.
14748 */
14749 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
14750 (ctxt->comp != NULL) &&
14751 (ctxt->base != NULL) &&
Kasimier T. Buchcik7cb3fa92006-06-06 15:27:46 +000014752 (ctxt->comp->nbStep > 2) &&
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014753 (ctxt->comp->last >= 0) &&
14754 (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014755 {
14756 xmlXPathRewriteDOSExpression(ctxt->comp,
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014757 &ctxt->comp->steps[ctxt->comp->last]);
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014758 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014759 }
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000014760 CHECK_ERROR;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014761 xmlXPathRunEval(ctxt, 0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014762}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014763
14764/**
14765 * xmlXPathEval:
14766 * @str: the XPath expression
14767 * @ctx: the XPath context
14768 *
14769 * Evaluate the XPath Location Path in the given context.
14770 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014771 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014772 * the caller has to free the object.
14773 */
14774xmlXPathObjectPtr
14775xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14776 xmlXPathParserContextPtr ctxt;
14777 xmlXPathObjectPtr res, tmp, init = NULL;
14778 int stack = 0;
14779
William M. Brackf13f77f2004-11-12 16:03:48 +000014780 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014781
William M. Brackf13f77f2004-11-12 16:03:48 +000014782 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014783
14784 ctxt = xmlXPathNewParserContext(str, ctx);
14785 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014786
14787 if (ctxt->value == NULL) {
14788 xmlGenericError(xmlGenericErrorContext,
14789 "xmlXPathEval: evaluation failed\n");
14790 res = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014791 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
14792#ifdef XPATH_STREAMING
14793 && (ctxt->comp->stream == NULL)
14794#endif
14795 ) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014796 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14797 res = NULL;
14798 } else {
14799 res = valuePop(ctxt);
14800 }
14801
14802 do {
14803 tmp = valuePop(ctxt);
14804 if (tmp != NULL) {
14805 if (tmp != init)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014806 stack++;
14807 xmlXPathReleaseObject(ctx, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014808 }
14809 } while (tmp != NULL);
14810 if ((stack != 0) && (res != NULL)) {
14811 xmlGenericError(xmlGenericErrorContext,
14812 "xmlXPathEval: %d object left on the stack\n",
14813 stack);
14814 }
14815 if (ctxt->error != XPATH_EXPRESSION_OK) {
14816 xmlXPathFreeObject(res);
14817 res = NULL;
14818 }
14819
Owen Taylor3473f882001-02-23 17:55:21 +000014820 xmlXPathFreeParserContext(ctxt);
14821 return(res);
14822}
14823
14824/**
14825 * xmlXPathEvalExpression:
14826 * @str: the XPath expression
14827 * @ctxt: the XPath context
14828 *
14829 * Evaluate the XPath expression in the given context.
14830 *
14831 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14832 * the caller has to free the object.
14833 */
14834xmlXPathObjectPtr
14835xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14836 xmlXPathParserContextPtr pctxt;
14837 xmlXPathObjectPtr res, tmp;
14838 int stack = 0;
14839
William M. Brackf13f77f2004-11-12 16:03:48 +000014840 CHECK_CTXT(ctxt)
Owen Taylor3473f882001-02-23 17:55:21 +000014841
William M. Brackf13f77f2004-11-12 16:03:48 +000014842 xmlXPathInit();
Owen Taylor3473f882001-02-23 17:55:21 +000014843
14844 pctxt = xmlXPathNewParserContext(str, ctxt);
14845 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000014846
14847 if (*pctxt->cur != 0) {
14848 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14849 res = NULL;
14850 } else {
14851 res = valuePop(pctxt);
14852 }
14853 do {
14854 tmp = valuePop(pctxt);
14855 if (tmp != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014856 xmlXPathReleaseObject(ctxt, tmp);
Owen Taylor3473f882001-02-23 17:55:21 +000014857 stack++;
14858 }
14859 } while (tmp != NULL);
14860 if ((stack != 0) && (res != NULL)) {
14861 xmlGenericError(xmlGenericErrorContext,
14862 "xmlXPathEvalExpression: %d object left on the stack\n",
14863 stack);
14864 }
14865 xmlXPathFreeParserContext(pctxt);
14866 return(res);
14867}
14868
Daniel Veillard42766c02002-08-22 20:52:17 +000014869/************************************************************************
14870 * *
14871 * Extra functions not pertaining to the XPath spec *
14872 * *
14873 ************************************************************************/
14874/**
14875 * xmlXPathEscapeUriFunction:
14876 * @ctxt: the XPath Parser context
14877 * @nargs: the number of arguments
14878 *
14879 * Implement the escape-uri() XPath function
14880 * string escape-uri(string $str, bool $escape-reserved)
14881 *
14882 * This function applies the URI escaping rules defined in section 2 of [RFC
14883 * 2396] to the string supplied as $uri-part, which typically represents all
14884 * or part of a URI. The effect of the function is to replace any special
14885 * character in the string by an escape sequence of the form %xx%yy...,
14886 * where xxyy... is the hexadecimal representation of the octets used to
14887 * represent the character in UTF-8.
14888 *
14889 * The set of characters that are escaped depends on the setting of the
14890 * boolean argument $escape-reserved.
14891 *
14892 * If $escape-reserved is true, all characters are escaped other than lower
14893 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14894 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14895 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14896 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14897 * A-F).
14898 *
14899 * If $escape-reserved is false, the behavior differs in that characters
14900 * referred to in [RFC 2396] as reserved characters are not escaped. These
14901 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14902 *
14903 * [RFC 2396] does not define whether escaped URIs should use lower case or
14904 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14905 * compared using string comparison functions, this function must always use
14906 * the upper-case letters A-F.
14907 *
14908 * Generally, $escape-reserved should be set to true when escaping a string
14909 * that is to form a single part of a URI, and to false when escaping an
14910 * entire URI or URI reference.
14911 *
14912 * In the case of non-ascii characters, the string is encoded according to
14913 * utf-8 and then converted according to RFC 2396.
14914 *
14915 * Examples
14916 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14917 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14918 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14919 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14920 *
14921 */
Daniel Veillard118aed72002-09-24 14:13:13 +000014922static void
Daniel Veillard42766c02002-08-22 20:52:17 +000014923xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14924 xmlXPathObjectPtr str;
14925 int escape_reserved;
14926 xmlBufferPtr target;
14927 xmlChar *cptr;
14928 xmlChar escape[4];
14929
14930 CHECK_ARITY(2);
14931
14932 escape_reserved = xmlXPathPopBoolean(ctxt);
14933
14934 CAST_TO_STRING;
14935 str = valuePop(ctxt);
14936
14937 target = xmlBufferCreate();
14938
14939 escape[0] = '%';
14940 escape[3] = 0;
14941
14942 if (target) {
14943 for (cptr = str->stringval; *cptr; cptr++) {
14944 if ((*cptr >= 'A' && *cptr <= 'Z') ||
14945 (*cptr >= 'a' && *cptr <= 'z') ||
14946 (*cptr >= '0' && *cptr <= '9') ||
14947 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
14948 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
14949 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14950 (*cptr == '%' &&
14951 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14952 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14953 (cptr[1] >= '0' && cptr[1] <= '9')) &&
14954 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14955 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14956 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14957 (!escape_reserved &&
14958 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14959 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14960 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14961 *cptr == ','))) {
14962 xmlBufferAdd(target, cptr, 1);
14963 } else {
14964 if ((*cptr >> 4) < 10)
14965 escape[1] = '0' + (*cptr >> 4);
14966 else
14967 escape[1] = 'A' - 10 + (*cptr >> 4);
14968 if ((*cptr & 0xF) < 10)
14969 escape[2] = '0' + (*cptr & 0xF);
14970 else
14971 escape[2] = 'A' - 10 + (*cptr & 0xF);
14972
14973 xmlBufferAdd(target, &escape[0], 3);
14974 }
14975 }
14976 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014977 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
14978 xmlBufferContent(target)));
Daniel Veillard42766c02002-08-22 20:52:17 +000014979 xmlBufferFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014980 xmlXPathReleaseObject(ctxt->context, str);
Daniel Veillard42766c02002-08-22 20:52:17 +000014981}
14982
Owen Taylor3473f882001-02-23 17:55:21 +000014983/**
14984 * xmlXPathRegisterAllFunctions:
14985 * @ctxt: the XPath context
14986 *
14987 * Registers all default XPath functions in this context
14988 */
14989void
14990xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
14991{
14992 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
14993 xmlXPathBooleanFunction);
14994 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
14995 xmlXPathCeilingFunction);
14996 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
14997 xmlXPathCountFunction);
14998 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
14999 xmlXPathConcatFunction);
15000 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15001 xmlXPathContainsFunction);
15002 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15003 xmlXPathIdFunction);
15004 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15005 xmlXPathFalseFunction);
15006 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15007 xmlXPathFloorFunction);
15008 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15009 xmlXPathLastFunction);
15010 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15011 xmlXPathLangFunction);
15012 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15013 xmlXPathLocalNameFunction);
15014 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15015 xmlXPathNotFunction);
15016 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15017 xmlXPathNameFunction);
15018 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15019 xmlXPathNamespaceURIFunction);
15020 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15021 xmlXPathNormalizeFunction);
15022 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15023 xmlXPathNumberFunction);
15024 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15025 xmlXPathPositionFunction);
15026 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15027 xmlXPathRoundFunction);
15028 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15029 xmlXPathStringFunction);
15030 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15031 xmlXPathStringLengthFunction);
15032 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15033 xmlXPathStartsWithFunction);
15034 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15035 xmlXPathSubstringFunction);
15036 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15037 xmlXPathSubstringBeforeFunction);
15038 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15039 xmlXPathSubstringAfterFunction);
15040 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15041 xmlXPathSumFunction);
15042 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15043 xmlXPathTrueFunction);
15044 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15045 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000015046
15047 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15048 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15049 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000015050}
15051
15052#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000015053#define bottom_xpath
15054#include "elfgcchack.h"