blob: 1b7117f11a04ac52b69df3401f388fa7ad1fae3e [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005 *f
Owen Taylor3473f882001-02-23 17:55:21 +00006 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011 * See Copyright for the status of this software
Owen Taylor3473f882001-02-23 17:55:21 +000012 *
Daniel Veillardc5d64342001-06-24 12:13:24 +000013 * Author: daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000014 *
Owen Taylor3473f882001-02-23 17:55:21 +000015 */
16
Daniel Veillard34ce8be2002-03-18 19:37:11 +000017#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000018#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000019
Owen Taylor3473f882001-02-23 17:55:21 +000020#include <string.h>
21
22#ifdef HAVE_SYS_TYPES_H
23#include <sys/types.h>
24#endif
25#ifdef HAVE_MATH_H
26#include <math.h>
27#endif
28#ifdef HAVE_FLOAT_H
29#include <float.h>
30#endif
Owen Taylor3473f882001-02-23 17:55:21 +000031#ifdef HAVE_CTYPE_H
32#include <ctype.h>
33#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000034#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000035#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000036#endif
Owen Taylor3473f882001-02-23 17:55:21 +000037
38#include <libxml/xmlmemory.h>
39#include <libxml/tree.h>
40#include <libxml/valid.h>
41#include <libxml/xpath.h>
42#include <libxml/xpathInternals.h>
43#include <libxml/parserInternals.h>
44#include <libxml/hash.h>
45#ifdef LIBXML_XPTR_ENABLED
46#include <libxml/xpointer.h>
47#endif
48#ifdef LIBXML_DEBUG_ENABLED
49#include <libxml/debugXML.h>
50#endif
51#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000052#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000053#include <libxml/globals.h>
Daniel Veillard56de87e2005-02-16 00:22:29 +000054#ifdef LIBXML_PATTERN_ENABLED
55#include <libxml/pattern.h>
56#endif
57
58#ifdef LIBXML_PATTERN_ENABLED
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000059#define XPATH_STREAMING
Daniel Veillard56de87e2005-02-16 00:22:29 +000060#endif
Owen Taylor3473f882001-02-23 17:55:21 +000061
Daniel Veillardd96f6d32003-10-07 21:25:12 +000062#define TODO \
63 xmlGenericError(xmlGenericErrorContext, \
64 "Unimplemented block at %s:%d\n", \
65 __FILE__, __LINE__);
66
William M. Brackd1757ab2004-10-02 22:07:48 +000067/*
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000068* XP_OPTIMIZED_NON_ELEM_COMPARISON:
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +000069* If defined, this will use xmlXPathCmpNodesExt() instead of
70* xmlXPathCmpNodes(). The new function is optimized comparison of
71* non-element nodes; actually it will speed up comparison only if
72* xmlXPathOrderDocElems() was called in order to index the elements of
73* a tree in document order; Libxslt does such an indexing, thus it will
74* benefit from this optimization.
75*/
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000076#define XP_OPTIMIZED_NON_ELEM_COMPARISON
77
78/*
79* XP_OPTIMIZED_FILTER_FIRST:
80* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
81* in a way, that it stop evaluation at the first node.
82*/
83#define XP_OPTIMIZED_FILTER_FIRST
84
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000085/*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000086* XP_DEBUG_OBJ_USAGE:
87* Internal flag to enable tracking of how much XPath objects have been
88* created.
89*/
90/* #define XP_DEBUG_OBJ_USAGE */
91
92/*
William M. Brackd1757ab2004-10-02 22:07:48 +000093 * TODO:
94 * There are a few spots where some tests are done which depend upon ascii
95 * data. These should be enhanced for full UTF8 support (see particularly
96 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
97 */
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000098
William M. Brack21e4ef22005-01-02 09:53:13 +000099#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000100
101/************************************************************************
102 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000103 * Floating point stuff *
104 * *
105 ************************************************************************/
106
Daniel Veillardc0631a62001-09-20 13:56:06 +0000107#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +0000108#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +0000109#endif
Daniel Veillardcda96922001-08-21 10:56:31 +0000110#include "trionan.c"
111
Owen Taylor3473f882001-02-23 17:55:21 +0000112/*
Owen Taylor3473f882001-02-23 17:55:21 +0000113 * The lack of portability of this section of the libc is annoying !
114 */
115double xmlXPathNAN = 0;
116double xmlXPathPINF = 1;
117double xmlXPathNINF = -1;
Daniel Veillard24505b02005-07-28 23:49:35 +0000118static double xmlXPathNZERO = 0; /* not exported from headers */
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000119static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000120
Owen Taylor3473f882001-02-23 17:55:21 +0000121/**
122 * xmlXPathInit:
123 *
124 * Initialize the XPath environment
125 */
126void
127xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000128 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +0000129
Bjorn Reese45029602001-08-21 09:23:53 +0000130 xmlXPathPINF = trio_pinf();
131 xmlXPathNINF = trio_ninf();
132 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000133 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +0000134
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000135 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000136}
137
Daniel Veillardcda96922001-08-21 10:56:31 +0000138/**
139 * xmlXPathIsNaN:
140 * @val: a double value
141 *
142 * Provides a portable isnan() function to detect whether a double
143 * is a NotaNumber. Based on trio code
144 * http://sourceforge.net/projects/ctrio/
145 *
146 * Returns 1 if the value is a NaN, 0 otherwise
147 */
148int
149xmlXPathIsNaN(double val) {
150 return(trio_isnan(val));
151}
152
153/**
154 * xmlXPathIsInf:
155 * @val: a double value
156 *
157 * Provides a portable isinf() function to detect whether a double
158 * is a +Infinite or -Infinite. Based on trio code
159 * http://sourceforge.net/projects/ctrio/
160 *
161 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
162 */
163int
164xmlXPathIsInf(double val) {
165 return(trio_isinf(val));
166}
167
Daniel Veillard4432df22003-09-28 18:58:27 +0000168#endif /* SCHEMAS or XPATH */
169#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000170/**
171 * xmlXPathGetSign:
172 * @val: a double value
173 *
174 * Provides a portable function to detect the sign of a double
175 * Modified from trio code
176 * http://sourceforge.net/projects/ctrio/
177 *
178 * Returns 1 if the value is Negative, 0 if positive
179 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000180static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000181xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000182 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000183}
184
185
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000186/*
187 * TODO: when compatibility allows remove all "fake node libxslt" strings
188 * the test should just be name[0] = ' '
189 */
190/* #define DEBUG */
191/* #define DEBUG_STEP */
192/* #define DEBUG_STEP_NTH */
193/* #define DEBUG_EXPR */
194/* #define DEBUG_EVAL_COUNTS */
195
196static xmlNs xmlXPathXMLNamespaceStruct = {
197 NULL,
198 XML_NAMESPACE_DECL,
199 XML_XML_NAMESPACE,
200 BAD_CAST "xml",
201 NULL
202};
203static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
204#ifndef LIBXML_THREAD_ENABLED
205/*
206 * Optimizer is disabled only when threaded apps are detected while
207 * the library ain't compiled for thread safety.
208 */
209static int xmlXPathDisableOptimizer = 0;
210#endif
211
Owen Taylor3473f882001-02-23 17:55:21 +0000212/************************************************************************
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000213 * *
214 * Error handling routines *
215 * *
216 ************************************************************************/
217
Daniel Veillard24505b02005-07-28 23:49:35 +0000218/**
219 * XP_ERRORNULL:
220 * @X: the error code
221 *
222 * Macro to raise an XPath error and return NULL.
223 */
224#define XP_ERRORNULL(X) \
225 { xmlXPathErr(ctxt, X); return(NULL); }
226
William M. Brack08171912003-12-29 02:52:11 +0000227/*
228 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
229 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000230static const char *xmlXPathErrorMessages[] = {
231 "Ok\n",
232 "Number encoding\n",
233 "Unfinished literal\n",
234 "Start of literal\n",
235 "Expected $ for variable reference\n",
236 "Undefined variable\n",
237 "Invalid predicate\n",
238 "Invalid expression\n",
239 "Missing closing curly brace\n",
240 "Unregistered function\n",
241 "Invalid operand\n",
242 "Invalid type\n",
243 "Invalid number of arguments\n",
244 "Invalid context size\n",
245 "Invalid context position\n",
246 "Memory allocation error\n",
247 "Syntax error\n",
248 "Resource error\n",
249 "Sub resource error\n",
250 "Undefined namespace prefix\n",
251 "Encoding error\n",
Daniel Veillard57b25162004-11-06 14:50:18 +0000252 "Char out of XML range\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000253 "Invalid or incomplete context\n",
254 "?? Unknown error ??\n" /* Must be last in the list! */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000255};
William M. Brackcd65bc92005-01-06 09:39:18 +0000256#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
257 sizeof(xmlXPathErrorMessages[0])) - 1)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000258/**
259 * xmlXPathErrMemory:
260 * @ctxt: an XPath context
261 * @extra: extra informations
262 *
263 * Handle a redefinition of attribute error
264 */
265static void
266xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
267{
268 if (ctxt != NULL) {
269 if (extra) {
270 xmlChar buf[200];
271
272 xmlStrPrintf(buf, 200,
273 BAD_CAST "Memory allocation failed : %s\n",
274 extra);
275 ctxt->lastError.message = (char *) xmlStrdup(buf);
276 } else {
277 ctxt->lastError.message = (char *)
278 xmlStrdup(BAD_CAST "Memory allocation failed\n");
279 }
280 ctxt->lastError.domain = XML_FROM_XPATH;
281 ctxt->lastError.code = XML_ERR_NO_MEMORY;
282 if (ctxt->error != NULL)
283 ctxt->error(ctxt->userData, &ctxt->lastError);
284 } else {
285 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000286 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000287 NULL, NULL, XML_FROM_XPATH,
288 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
289 extra, NULL, NULL, 0, 0,
290 "Memory allocation failed : %s\n", extra);
291 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000292 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000293 NULL, NULL, XML_FROM_XPATH,
294 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
295 NULL, NULL, NULL, 0, 0,
296 "Memory allocation failed\n");
297 }
298}
299
300/**
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000301 * xmlXPathPErrMemory:
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000302 * @ctxt: an XPath parser context
303 * @extra: extra informations
304 *
305 * Handle a redefinition of attribute error
306 */
307static void
308xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
309{
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000310 if (ctxt == NULL)
311 xmlXPathErrMemory(NULL, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000312 else {
313 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000314 xmlXPathErrMemory(ctxt->context, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000315 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000316}
317
318/**
319 * xmlXPathErr:
320 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000321 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000322 *
William M. Brackcd65bc92005-01-06 09:39:18 +0000323 * Handle an XPath error
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000324 */
325void
326xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
327{
William M. Brackcd65bc92005-01-06 09:39:18 +0000328 if ((error < 0) || (error > MAXERRNO))
329 error = MAXERRNO;
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000330 if (ctxt == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000331 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000332 NULL, NULL, XML_FROM_XPATH,
333 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
334 XML_ERR_ERROR, NULL, 0,
335 NULL, NULL, NULL, 0, 0,
336 xmlXPathErrorMessages[error]);
337 return;
338 }
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000339 ctxt->error = error;
340 if (ctxt->context == NULL) {
341 __xmlRaiseError(NULL, NULL, NULL,
342 NULL, NULL, XML_FROM_XPATH,
343 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
344 XML_ERR_ERROR, NULL, 0,
345 (const char *) ctxt->base, NULL, NULL,
346 ctxt->cur - ctxt->base, 0,
347 xmlXPathErrorMessages[error]);
348 return;
349 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +0000350
351 /* cleanup current last error */
352 xmlResetError(&ctxt->context->lastError);
353
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000354 ctxt->context->lastError.domain = XML_FROM_XPATH;
355 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
356 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000357 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000358 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
359 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
360 ctxt->context->lastError.node = ctxt->context->debugNode;
361 if (ctxt->context->error != NULL) {
362 ctxt->context->error(ctxt->context->userData,
363 &ctxt->context->lastError);
364 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000365 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000366 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
367 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
368 XML_ERR_ERROR, NULL, 0,
369 (const char *) ctxt->base, NULL, NULL,
370 ctxt->cur - ctxt->base, 0,
371 xmlXPathErrorMessages[error]);
372 }
373
374}
375
376/**
377 * xmlXPatherror:
378 * @ctxt: the XPath Parser context
379 * @file: the file name
380 * @line: the line number
381 * @no: the error number
382 *
383 * Formats an error message.
384 */
385void
386xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
387 int line ATTRIBUTE_UNUSED, int no) {
388 xmlXPathErr(ctxt, no);
389}
390
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000391/************************************************************************
392 * *
393 * Utilities *
394 * *
395 ************************************************************************/
396
397/**
398 * xsltPointerList:
399 *
400 * Pointer-list for various purposes.
401 */
402typedef struct _xmlPointerList xmlPointerList;
403typedef xmlPointerList *xmlPointerListPtr;
404struct _xmlPointerList {
405 void **items;
406 int number;
407 int size;
408};
409/*
410* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
411* and here, we should make the functions public.
412*/
413static int
414xmlPointerListAddSize(xmlPointerListPtr list,
415 void *item,
416 int initialSize)
417{
418 if (list->items == NULL) {
419 if (initialSize <= 0)
420 initialSize = 1;
421 list->items = (void **) xmlMalloc(
422 initialSize * sizeof(void *));
423 if (list->items == NULL) {
424 xmlXPathErrMemory(NULL,
425 "xmlPointerListCreate: allocating item\n");
426 return(-1);
427 }
428 list->number = 0;
429 list->size = initialSize;
430 } else if (list->size <= list->number) {
431 list->size *= 2;
432 list->items = (void **) xmlRealloc(list->items,
433 list->size * sizeof(void *));
434 if (list->items == NULL) {
435 xmlXPathErrMemory(NULL,
436 "xmlPointerListCreate: re-allocating item\n");
437 list->size = 0;
438 return(-1);
439 }
440 }
441 list->items[list->number++] = item;
442 return(0);
443}
444
445/**
446 * xsltPointerListCreate:
447 *
448 * Creates an xsltPointerList structure.
449 *
450 * Returns a xsltPointerList structure or NULL in case of an error.
451 */
452static xmlPointerListPtr
453xmlPointerListCreate(int initialSize)
454{
455 xmlPointerListPtr ret;
456
457 ret = xmlMalloc(sizeof(xmlPointerList));
458 if (ret == NULL) {
459 xmlXPathErrMemory(NULL,
460 "xmlPointerListCreate: allocating item\n");
461 return (NULL);
462 }
463 memset(ret, 0, sizeof(xmlPointerList));
464 if (initialSize > 0) {
465 xmlPointerListAddSize(ret, NULL, initialSize);
466 ret->number = 0;
467 }
468 return (ret);
469}
470
471/**
472 * xsltPointerListFree:
473 *
474 * Frees the xsltPointerList structure. This does not free
475 * the content of the list.
476 */
477static void
478xmlPointerListFree(xmlPointerListPtr list)
479{
480 if (list == NULL)
481 return;
482 if (list->items != NULL)
483 xmlFree(list->items);
484 xmlFree(list);
485}
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000486
487/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000488 * *
489 * Parser Types *
490 * *
491 ************************************************************************/
492
493/*
494 * Types are private:
495 */
496
497typedef enum {
498 XPATH_OP_END=0,
499 XPATH_OP_AND,
500 XPATH_OP_OR,
501 XPATH_OP_EQUAL,
502 XPATH_OP_CMP,
503 XPATH_OP_PLUS,
504 XPATH_OP_MULT,
505 XPATH_OP_UNION,
506 XPATH_OP_ROOT,
507 XPATH_OP_NODE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000508 XPATH_OP_RESET, /* 10 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000509 XPATH_OP_COLLECT,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000510 XPATH_OP_VALUE, /* 12 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000511 XPATH_OP_VARIABLE,
512 XPATH_OP_FUNCTION,
513 XPATH_OP_ARG,
514 XPATH_OP_PREDICATE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000515 XPATH_OP_FILTER, /* 17 */
516 XPATH_OP_SORT /* 18 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000517#ifdef LIBXML_XPTR_ENABLED
518 ,XPATH_OP_RANGETO
519#endif
520} xmlXPathOp;
521
522typedef enum {
523 AXIS_ANCESTOR = 1,
524 AXIS_ANCESTOR_OR_SELF,
525 AXIS_ATTRIBUTE,
526 AXIS_CHILD,
527 AXIS_DESCENDANT,
528 AXIS_DESCENDANT_OR_SELF,
529 AXIS_FOLLOWING,
530 AXIS_FOLLOWING_SIBLING,
531 AXIS_NAMESPACE,
532 AXIS_PARENT,
533 AXIS_PRECEDING,
534 AXIS_PRECEDING_SIBLING,
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +0000535 AXIS_SELF
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000536} xmlXPathAxisVal;
537
538typedef enum {
539 NODE_TEST_NONE = 0,
540 NODE_TEST_TYPE = 1,
541 NODE_TEST_PI = 2,
542 NODE_TEST_ALL = 3,
543 NODE_TEST_NS = 4,
544 NODE_TEST_NAME = 5
545} xmlXPathTestVal;
546
547typedef enum {
548 NODE_TYPE_NODE = 0,
549 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
550 NODE_TYPE_TEXT = XML_TEXT_NODE,
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +0000551 NODE_TYPE_PI = XML_PI_NODE
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000552} xmlXPathTypeVal;
553
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +0000554#define XP_REWRITE_DOS_CHILD_ELEM 1
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000555
556typedef struct _xmlXPathStepOp xmlXPathStepOp;
557typedef xmlXPathStepOp *xmlXPathStepOpPtr;
558struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000559 xmlXPathOp op; /* The identifier of the operation */
560 int ch1; /* First child */
561 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000562 int value;
563 int value2;
564 int value3;
565 void *value4;
566 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000567 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000568 void *cacheURI;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +0000569 int rewriteType;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000570};
571
572struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000573 int nbStep; /* Number of steps in this expression */
574 int maxStep; /* Maximum number of steps allocated */
575 xmlXPathStepOp *steps; /* ops for computation of this expression */
576 int last; /* index of last step in expression */
577 xmlChar *expr; /* the expression being computed */
Daniel Veillard4773df22004-01-23 13:15:13 +0000578 xmlDictPtr dict; /* the dictionnary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000579#ifdef DEBUG_EVAL_COUNTS
580 int nb;
581 xmlChar *string;
582#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000583#ifdef XPATH_STREAMING
584 xmlPatternPtr stream;
585#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000586};
587
588/************************************************************************
589 * *
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000590 * Forward declarations *
591 * *
592 ************************************************************************/
593static void
594xmlXPathFreeValueTree(xmlNodeSetPtr obj);
595static void
596xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
597static int
598xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
599 xmlXPathStepOpPtr op, xmlNodePtr *first);
600static int
601xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +0000602 xmlXPathStepOpPtr op,
603 int isPredicate);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000604
605/************************************************************************
606 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000607 * Parser Type functions *
608 * *
609 ************************************************************************/
610
611/**
612 * xmlXPathNewCompExpr:
613 *
614 * Create a new Xpath component
615 *
616 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
617 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000618static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000619xmlXPathNewCompExpr(void) {
620 xmlXPathCompExprPtr cur;
621
622 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
623 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000624 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000625 return(NULL);
626 }
627 memset(cur, 0, sizeof(xmlXPathCompExpr));
628 cur->maxStep = 10;
629 cur->nbStep = 0;
630 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
631 sizeof(xmlXPathStepOp));
632 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000633 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000634 xmlFree(cur);
635 return(NULL);
636 }
637 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
638 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000639#ifdef DEBUG_EVAL_COUNTS
640 cur->nb = 0;
641#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000642 return(cur);
643}
644
645/**
646 * xmlXPathFreeCompExpr:
647 * @comp: an XPATH comp
648 *
649 * Free up the memory allocated by @comp
650 */
651void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000652xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
653{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000654 xmlXPathStepOpPtr op;
655 int i;
656
657 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000658 return;
Daniel Veillard4773df22004-01-23 13:15:13 +0000659 if (comp->dict == NULL) {
660 for (i = 0; i < comp->nbStep; i++) {
661 op = &comp->steps[i];
662 if (op->value4 != NULL) {
663 if (op->op == XPATH_OP_VALUE)
664 xmlXPathFreeObject(op->value4);
665 else
666 xmlFree(op->value4);
667 }
668 if (op->value5 != NULL)
669 xmlFree(op->value5);
670 }
671 } else {
672 for (i = 0; i < comp->nbStep; i++) {
673 op = &comp->steps[i];
674 if (op->value4 != NULL) {
675 if (op->op == XPATH_OP_VALUE)
676 xmlXPathFreeObject(op->value4);
677 }
678 }
679 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000680 }
681 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000682 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000683 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000684#ifdef DEBUG_EVAL_COUNTS
685 if (comp->string != NULL) {
686 xmlFree(comp->string);
687 }
688#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000689#ifdef XPATH_STREAMING
690 if (comp->stream != NULL) {
691 xmlFreePatternList(comp->stream);
692 }
693#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000694 if (comp->expr != NULL) {
695 xmlFree(comp->expr);
696 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000697
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000698 xmlFree(comp);
699}
700
701/**
702 * xmlXPathCompExprAdd:
703 * @comp: the compiled expression
704 * @ch1: first child index
705 * @ch2: second child index
706 * @op: an op
707 * @value: the first int value
708 * @value2: the second int value
709 * @value3: the third int value
710 * @value4: the first string value
711 * @value5: the second string value
712 *
William M. Brack08171912003-12-29 02:52:11 +0000713 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000714 *
715 * Returns -1 in case of failure, the index otherwise
716 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000717static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000718xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
719 xmlXPathOp op, int value,
720 int value2, int value3, void *value4, void *value5) {
721 if (comp->nbStep >= comp->maxStep) {
722 xmlXPathStepOp *real;
723
724 comp->maxStep *= 2;
725 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
726 comp->maxStep * sizeof(xmlXPathStepOp));
727 if (real == NULL) {
728 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000729 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000730 return(-1);
731 }
732 comp->steps = real;
733 }
734 comp->last = comp->nbStep;
Kasimier T. Buchcik6422d912006-06-26 14:31:53 +0000735 comp->steps[comp->nbStep].rewriteType = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000736 comp->steps[comp->nbStep].ch1 = ch1;
737 comp->steps[comp->nbStep].ch2 = ch2;
738 comp->steps[comp->nbStep].op = op;
739 comp->steps[comp->nbStep].value = value;
740 comp->steps[comp->nbStep].value2 = value2;
741 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +0000742 if ((comp->dict != NULL) &&
743 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
744 (op == XPATH_OP_COLLECT))) {
745 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000746 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000747 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000748 xmlFree(value4);
749 } else
750 comp->steps[comp->nbStep].value4 = NULL;
751 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000752 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000753 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000754 xmlFree(value5);
755 } else
756 comp->steps[comp->nbStep].value5 = NULL;
757 } else {
758 comp->steps[comp->nbStep].value4 = value4;
759 comp->steps[comp->nbStep].value5 = value5;
760 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000761 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000762 return(comp->nbStep++);
763}
764
Daniel Veillardf06307e2001-07-03 10:35:50 +0000765/**
766 * xmlXPathCompSwap:
767 * @comp: the compiled expression
768 * @op: operation index
769 *
770 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000771 */
772static void
773xmlXPathCompSwap(xmlXPathStepOpPtr op) {
774 int tmp;
775
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000776#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000777 /*
778 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +0000779 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +0000780 * application
781 */
782 if (xmlXPathDisableOptimizer)
783 return;
784#endif
785
Daniel Veillardf06307e2001-07-03 10:35:50 +0000786 tmp = op->ch1;
787 op->ch1 = op->ch2;
788 op->ch2 = tmp;
789}
790
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000791#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
792 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
793 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000794#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
795 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
796 (op), (val), (val2), (val3), (val4), (val5))
797
798#define PUSH_LEAVE_EXPR(op, val, val2) \
799xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
800
801#define PUSH_UNARY_EXPR(op, ch, val, val2) \
802xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
803
804#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +0000805xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
806 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000807
808/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000809 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000810 * XPath object cache structures *
811 * *
812 ************************************************************************/
813
814/* #define XP_DEFAULT_CACHE_ON */
815
Kasimier T. Buchcik58694692006-05-31 12:37:28 +0000816#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000817
Kasimier T. Buchcik58694692006-05-31 12:37:28 +0000818typedef struct _xmlXPathContextCache xmlXPathContextCache;
819typedef xmlXPathContextCache *xmlXPathContextCachePtr;
820struct _xmlXPathContextCache {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +0000821 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
822 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
823 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
824 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
825 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000826 int maxNodeset;
827 int maxString;
828 int maxBoolean;
829 int maxNumber;
830 int maxMisc;
831#ifdef XP_DEBUG_OBJ_USAGE
832 int dbgCachedAll;
833 int dbgCachedNodeset;
834 int dbgCachedString;
835 int dbgCachedBool;
836 int dbgCachedNumber;
837 int dbgCachedPoint;
838 int dbgCachedRange;
839 int dbgCachedLocset;
840 int dbgCachedUsers;
841 int dbgCachedXSLTTree;
842 int dbgCachedUndefined;
843
844
845 int dbgReusedAll;
846 int dbgReusedNodeset;
847 int dbgReusedString;
848 int dbgReusedBool;
849 int dbgReusedNumber;
850 int dbgReusedPoint;
851 int dbgReusedRange;
852 int dbgReusedLocset;
853 int dbgReusedUsers;
854 int dbgReusedXSLTTree;
855 int dbgReusedUndefined;
856
857#endif
858};
859
860/************************************************************************
861 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000862 * Debugging related functions *
863 * *
864 ************************************************************************/
865
Owen Taylor3473f882001-02-23 17:55:21 +0000866#define STRANGE \
867 xmlGenericError(xmlGenericErrorContext, \
868 "Internal error at %s:%d\n", \
869 __FILE__, __LINE__);
870
871#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000872static void
873xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000874 int i;
875 char shift[100];
876
877 for (i = 0;((i < depth) && (i < 25));i++)
878 shift[2 * i] = shift[2 * i + 1] = ' ';
879 shift[2 * i] = shift[2 * i + 1] = 0;
880 if (cur == NULL) {
881 fprintf(output, shift);
882 fprintf(output, "Node is NULL !\n");
883 return;
884
885 }
886
887 if ((cur->type == XML_DOCUMENT_NODE) ||
888 (cur->type == XML_HTML_DOCUMENT_NODE)) {
889 fprintf(output, shift);
890 fprintf(output, " /\n");
891 } else if (cur->type == XML_ATTRIBUTE_NODE)
892 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
893 else
894 xmlDebugDumpOneNode(output, cur, depth);
895}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000896static void
897xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000898 xmlNodePtr tmp;
899 int i;
900 char shift[100];
901
902 for (i = 0;((i < depth) && (i < 25));i++)
903 shift[2 * i] = shift[2 * i + 1] = ' ';
904 shift[2 * i] = shift[2 * i + 1] = 0;
905 if (cur == NULL) {
906 fprintf(output, shift);
907 fprintf(output, "Node is NULL !\n");
908 return;
909
910 }
911
912 while (cur != NULL) {
913 tmp = cur;
914 cur = cur->next;
915 xmlDebugDumpOneNode(output, tmp, depth);
916 }
917}
Owen Taylor3473f882001-02-23 17:55:21 +0000918
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000919static void
920xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000921 int i;
922 char shift[100];
923
924 for (i = 0;((i < depth) && (i < 25));i++)
925 shift[2 * i] = shift[2 * i + 1] = ' ';
926 shift[2 * i] = shift[2 * i + 1] = 0;
927
928 if (cur == NULL) {
929 fprintf(output, shift);
930 fprintf(output, "NodeSet is NULL !\n");
931 return;
932
933 }
934
Daniel Veillard911f49a2001-04-07 15:39:35 +0000935 if (cur != NULL) {
936 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
937 for (i = 0;i < cur->nodeNr;i++) {
938 fprintf(output, shift);
939 fprintf(output, "%d", i + 1);
940 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
941 }
Owen Taylor3473f882001-02-23 17:55:21 +0000942 }
943}
944
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000945static void
946xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000947 int i;
948 char shift[100];
949
950 for (i = 0;((i < depth) && (i < 25));i++)
951 shift[2 * i] = shift[2 * i + 1] = ' ';
952 shift[2 * i] = shift[2 * i + 1] = 0;
953
954 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
955 fprintf(output, shift);
956 fprintf(output, "Value Tree is NULL !\n");
957 return;
958
959 }
960
961 fprintf(output, shift);
962 fprintf(output, "%d", i + 1);
963 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
964}
Owen Taylor3473f882001-02-23 17:55:21 +0000965#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000966static void
967xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000968 int i;
969 char shift[100];
970
971 for (i = 0;((i < depth) && (i < 25));i++)
972 shift[2 * i] = shift[2 * i + 1] = ' ';
973 shift[2 * i] = shift[2 * i + 1] = 0;
974
975 if (cur == NULL) {
976 fprintf(output, shift);
977 fprintf(output, "LocationSet is NULL !\n");
978 return;
979
980 }
981
982 for (i = 0;i < cur->locNr;i++) {
983 fprintf(output, shift);
984 fprintf(output, "%d : ", i + 1);
985 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
986 }
987}
Daniel Veillard017b1082001-06-21 11:20:21 +0000988#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000989
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000990/**
991 * xmlXPathDebugDumpObject:
992 * @output: the FILE * to dump the output
993 * @cur: the object to inspect
994 * @depth: indentation level
995 *
996 * Dump the content of the object for debugging purposes
997 */
998void
999xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001000 int i;
1001 char shift[100];
1002
Daniel Veillarda82b1822004-11-08 16:24:57 +00001003 if (output == NULL) return;
1004
Owen Taylor3473f882001-02-23 17:55:21 +00001005 for (i = 0;((i < depth) && (i < 25));i++)
1006 shift[2 * i] = shift[2 * i + 1] = ' ';
1007 shift[2 * i] = shift[2 * i + 1] = 0;
1008
Kasimier T. Buchcik97258712006-01-05 12:30:43 +00001009
1010 fprintf(output, shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001011
1012 if (cur == NULL) {
1013 fprintf(output, "Object is empty (NULL)\n");
1014 return;
1015 }
1016 switch(cur->type) {
1017 case XPATH_UNDEFINED:
1018 fprintf(output, "Object is uninitialized\n");
1019 break;
1020 case XPATH_NODESET:
1021 fprintf(output, "Object is a Node Set :\n");
1022 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1023 break;
1024 case XPATH_XSLT_TREE:
1025 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001026 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +00001027 break;
1028 case XPATH_BOOLEAN:
1029 fprintf(output, "Object is a Boolean : ");
1030 if (cur->boolval) fprintf(output, "true\n");
1031 else fprintf(output, "false\n");
1032 break;
1033 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +00001034 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001035 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001036 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001037 break;
1038 case -1:
1039 fprintf(output, "Object is a number : -Infinity\n");
1040 break;
1041 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001042 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001043 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001044 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1045 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001046 } else {
1047 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1048 }
1049 }
Owen Taylor3473f882001-02-23 17:55:21 +00001050 break;
1051 case XPATH_STRING:
1052 fprintf(output, "Object is a string : ");
1053 xmlDebugDumpString(output, cur->stringval);
1054 fprintf(output, "\n");
1055 break;
1056 case XPATH_POINT:
1057 fprintf(output, "Object is a point : index %d in node", cur->index);
1058 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1059 fprintf(output, "\n");
1060 break;
1061 case XPATH_RANGE:
1062 if ((cur->user2 == NULL) ||
1063 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1064 fprintf(output, "Object is a collapsed range :\n");
1065 fprintf(output, shift);
1066 if (cur->index >= 0)
1067 fprintf(output, "index %d in ", cur->index);
1068 fprintf(output, "node\n");
1069 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1070 depth + 1);
1071 } else {
1072 fprintf(output, "Object is a range :\n");
1073 fprintf(output, shift);
1074 fprintf(output, "From ");
1075 if (cur->index >= 0)
1076 fprintf(output, "index %d in ", cur->index);
1077 fprintf(output, "node\n");
1078 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1079 depth + 1);
1080 fprintf(output, shift);
1081 fprintf(output, "To ");
1082 if (cur->index2 >= 0)
1083 fprintf(output, "index %d in ", cur->index2);
1084 fprintf(output, "node\n");
1085 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1086 depth + 1);
1087 fprintf(output, "\n");
1088 }
1089 break;
1090 case XPATH_LOCATIONSET:
1091#if defined(LIBXML_XPTR_ENABLED)
1092 fprintf(output, "Object is a Location Set:\n");
1093 xmlXPathDebugDumpLocationSet(output,
1094 (xmlLocationSetPtr) cur->user, depth);
1095#endif
1096 break;
1097 case XPATH_USERS:
1098 fprintf(output, "Object is user defined\n");
1099 break;
1100 }
1101}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001102
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001103static void
1104xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001105 xmlXPathStepOpPtr op, int depth) {
1106 int i;
1107 char shift[100];
1108
1109 for (i = 0;((i < depth) && (i < 25));i++)
1110 shift[2 * i] = shift[2 * i + 1] = ' ';
1111 shift[2 * i] = shift[2 * i + 1] = 0;
1112
1113 fprintf(output, shift);
1114 if (op == NULL) {
1115 fprintf(output, "Step is NULL\n");
1116 return;
1117 }
1118 switch (op->op) {
1119 case XPATH_OP_END:
1120 fprintf(output, "END"); break;
1121 case XPATH_OP_AND:
1122 fprintf(output, "AND"); break;
1123 case XPATH_OP_OR:
1124 fprintf(output, "OR"); break;
1125 case XPATH_OP_EQUAL:
1126 if (op->value)
1127 fprintf(output, "EQUAL =");
1128 else
1129 fprintf(output, "EQUAL !=");
1130 break;
1131 case XPATH_OP_CMP:
1132 if (op->value)
1133 fprintf(output, "CMP <");
1134 else
1135 fprintf(output, "CMP >");
1136 if (!op->value2)
1137 fprintf(output, "=");
1138 break;
1139 case XPATH_OP_PLUS:
1140 if (op->value == 0)
1141 fprintf(output, "PLUS -");
1142 else if (op->value == 1)
1143 fprintf(output, "PLUS +");
1144 else if (op->value == 2)
1145 fprintf(output, "PLUS unary -");
1146 else if (op->value == 3)
1147 fprintf(output, "PLUS unary - -");
1148 break;
1149 case XPATH_OP_MULT:
1150 if (op->value == 0)
1151 fprintf(output, "MULT *");
1152 else if (op->value == 1)
1153 fprintf(output, "MULT div");
1154 else
1155 fprintf(output, "MULT mod");
1156 break;
1157 case XPATH_OP_UNION:
1158 fprintf(output, "UNION"); break;
1159 case XPATH_OP_ROOT:
1160 fprintf(output, "ROOT"); break;
1161 case XPATH_OP_NODE:
1162 fprintf(output, "NODE"); break;
1163 case XPATH_OP_RESET:
1164 fprintf(output, "RESET"); break;
1165 case XPATH_OP_SORT:
1166 fprintf(output, "SORT"); break;
1167 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +00001168 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1169 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1170 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001171 const xmlChar *prefix = op->value4;
1172 const xmlChar *name = op->value5;
1173
1174 fprintf(output, "COLLECT ");
1175 switch (axis) {
1176 case AXIS_ANCESTOR:
1177 fprintf(output, " 'ancestors' "); break;
1178 case AXIS_ANCESTOR_OR_SELF:
1179 fprintf(output, " 'ancestors-or-self' "); break;
1180 case AXIS_ATTRIBUTE:
1181 fprintf(output, " 'attributes' "); break;
1182 case AXIS_CHILD:
1183 fprintf(output, " 'child' "); break;
1184 case AXIS_DESCENDANT:
1185 fprintf(output, " 'descendant' "); break;
1186 case AXIS_DESCENDANT_OR_SELF:
1187 fprintf(output, " 'descendant-or-self' "); break;
1188 case AXIS_FOLLOWING:
1189 fprintf(output, " 'following' "); break;
1190 case AXIS_FOLLOWING_SIBLING:
1191 fprintf(output, " 'following-siblings' "); break;
1192 case AXIS_NAMESPACE:
1193 fprintf(output, " 'namespace' "); break;
1194 case AXIS_PARENT:
1195 fprintf(output, " 'parent' "); break;
1196 case AXIS_PRECEDING:
1197 fprintf(output, " 'preceding' "); break;
1198 case AXIS_PRECEDING_SIBLING:
1199 fprintf(output, " 'preceding-sibling' "); break;
1200 case AXIS_SELF:
1201 fprintf(output, " 'self' "); break;
1202 }
1203 switch (test) {
1204 case NODE_TEST_NONE:
1205 fprintf(output, "'none' "); break;
1206 case NODE_TEST_TYPE:
1207 fprintf(output, "'type' "); break;
1208 case NODE_TEST_PI:
1209 fprintf(output, "'PI' "); break;
1210 case NODE_TEST_ALL:
1211 fprintf(output, "'all' "); break;
1212 case NODE_TEST_NS:
1213 fprintf(output, "'namespace' "); break;
1214 case NODE_TEST_NAME:
1215 fprintf(output, "'name' "); break;
1216 }
1217 switch (type) {
1218 case NODE_TYPE_NODE:
1219 fprintf(output, "'node' "); break;
1220 case NODE_TYPE_COMMENT:
1221 fprintf(output, "'comment' "); break;
1222 case NODE_TYPE_TEXT:
1223 fprintf(output, "'text' "); break;
1224 case NODE_TYPE_PI:
1225 fprintf(output, "'PI' "); break;
1226 }
1227 if (prefix != NULL)
1228 fprintf(output, "%s:", prefix);
1229 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001230 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001231 break;
1232
1233 }
1234 case XPATH_OP_VALUE: {
1235 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1236
1237 fprintf(output, "ELEM ");
1238 xmlXPathDebugDumpObject(output, object, 0);
1239 goto finish;
1240 }
1241 case XPATH_OP_VARIABLE: {
1242 const xmlChar *prefix = op->value5;
1243 const xmlChar *name = op->value4;
1244
1245 if (prefix != NULL)
1246 fprintf(output, "VARIABLE %s:%s", prefix, name);
1247 else
1248 fprintf(output, "VARIABLE %s", name);
1249 break;
1250 }
1251 case XPATH_OP_FUNCTION: {
1252 int nbargs = op->value;
1253 const xmlChar *prefix = op->value5;
1254 const xmlChar *name = op->value4;
1255
1256 if (prefix != NULL)
1257 fprintf(output, "FUNCTION %s:%s(%d args)",
1258 prefix, name, nbargs);
1259 else
1260 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1261 break;
1262 }
1263 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1264 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001265 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001266#ifdef LIBXML_XPTR_ENABLED
1267 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1268#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001269 default:
1270 fprintf(output, "UNKNOWN %d\n", op->op); return;
1271 }
1272 fprintf(output, "\n");
1273finish:
1274 if (op->ch1 >= 0)
1275 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1276 if (op->ch2 >= 0)
1277 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1278}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001279
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001280/**
1281 * xmlXPathDebugDumpCompExpr:
1282 * @output: the FILE * for the output
1283 * @comp: the precompiled XPath expression
1284 * @depth: the indentation level.
1285 *
1286 * Dumps the tree of the compiled XPath expression.
1287 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001288void
1289xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1290 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001291 int i;
1292 char shift[100];
1293
Daniel Veillarda82b1822004-11-08 16:24:57 +00001294 if ((output == NULL) || (comp == NULL)) return;
1295
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001296 for (i = 0;((i < depth) && (i < 25));i++)
1297 shift[2 * i] = shift[2 * i + 1] = ' ';
1298 shift[2 * i] = shift[2 * i + 1] = 0;
1299
1300 fprintf(output, shift);
1301
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001302 fprintf(output, "Compiled Expression : %d elements\n",
1303 comp->nbStep);
1304 i = comp->last;
1305 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1306}
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001307
1308#ifdef XP_DEBUG_OBJ_USAGE
1309
1310/*
1311* XPath object usage related debugging variables.
1312*/
1313static int xmlXPathDebugObjCounterUndefined = 0;
1314static int xmlXPathDebugObjCounterNodeset = 0;
1315static int xmlXPathDebugObjCounterBool = 0;
1316static int xmlXPathDebugObjCounterNumber = 0;
1317static int xmlXPathDebugObjCounterString = 0;
1318static int xmlXPathDebugObjCounterPoint = 0;
1319static int xmlXPathDebugObjCounterRange = 0;
1320static int xmlXPathDebugObjCounterLocset = 0;
1321static int xmlXPathDebugObjCounterUsers = 0;
1322static int xmlXPathDebugObjCounterXSLTTree = 0;
1323static int xmlXPathDebugObjCounterAll = 0;
1324
1325static int xmlXPathDebugObjTotalUndefined = 0;
1326static int xmlXPathDebugObjTotalNodeset = 0;
1327static int xmlXPathDebugObjTotalBool = 0;
1328static int xmlXPathDebugObjTotalNumber = 0;
1329static int xmlXPathDebugObjTotalString = 0;
1330static int xmlXPathDebugObjTotalPoint = 0;
1331static int xmlXPathDebugObjTotalRange = 0;
1332static int xmlXPathDebugObjTotalLocset = 0;
1333static int xmlXPathDebugObjTotalUsers = 0;
1334static int xmlXPathDebugObjTotalXSLTTree = 0;
1335static int xmlXPathDebugObjTotalAll = 0;
1336
1337static int xmlXPathDebugObjMaxUndefined = 0;
1338static int xmlXPathDebugObjMaxNodeset = 0;
1339static int xmlXPathDebugObjMaxBool = 0;
1340static int xmlXPathDebugObjMaxNumber = 0;
1341static int xmlXPathDebugObjMaxString = 0;
1342static int xmlXPathDebugObjMaxPoint = 0;
1343static int xmlXPathDebugObjMaxRange = 0;
1344static int xmlXPathDebugObjMaxLocset = 0;
1345static int xmlXPathDebugObjMaxUsers = 0;
1346static int xmlXPathDebugObjMaxXSLTTree = 0;
1347static int xmlXPathDebugObjMaxAll = 0;
1348
1349/* REVISIT TODO: Make this static when committing */
1350static void
1351xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1352{
1353 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001354 if (ctxt->cache != NULL) {
1355 xmlXPathContextCachePtr cache =
1356 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001357
1358 cache->dbgCachedAll = 0;
1359 cache->dbgCachedNodeset = 0;
1360 cache->dbgCachedString = 0;
1361 cache->dbgCachedBool = 0;
1362 cache->dbgCachedNumber = 0;
1363 cache->dbgCachedPoint = 0;
1364 cache->dbgCachedRange = 0;
1365 cache->dbgCachedLocset = 0;
1366 cache->dbgCachedUsers = 0;
1367 cache->dbgCachedXSLTTree = 0;
1368 cache->dbgCachedUndefined = 0;
1369
1370 cache->dbgReusedAll = 0;
1371 cache->dbgReusedNodeset = 0;
1372 cache->dbgReusedString = 0;
1373 cache->dbgReusedBool = 0;
1374 cache->dbgReusedNumber = 0;
1375 cache->dbgReusedPoint = 0;
1376 cache->dbgReusedRange = 0;
1377 cache->dbgReusedLocset = 0;
1378 cache->dbgReusedUsers = 0;
1379 cache->dbgReusedXSLTTree = 0;
1380 cache->dbgReusedUndefined = 0;
1381 }
1382 }
1383
1384 xmlXPathDebugObjCounterUndefined = 0;
1385 xmlXPathDebugObjCounterNodeset = 0;
1386 xmlXPathDebugObjCounterBool = 0;
1387 xmlXPathDebugObjCounterNumber = 0;
1388 xmlXPathDebugObjCounterString = 0;
1389 xmlXPathDebugObjCounterPoint = 0;
1390 xmlXPathDebugObjCounterRange = 0;
1391 xmlXPathDebugObjCounterLocset = 0;
1392 xmlXPathDebugObjCounterUsers = 0;
1393 xmlXPathDebugObjCounterXSLTTree = 0;
1394 xmlXPathDebugObjCounterAll = 0;
1395
1396 xmlXPathDebugObjTotalUndefined = 0;
1397 xmlXPathDebugObjTotalNodeset = 0;
1398 xmlXPathDebugObjTotalBool = 0;
1399 xmlXPathDebugObjTotalNumber = 0;
1400 xmlXPathDebugObjTotalString = 0;
1401 xmlXPathDebugObjTotalPoint = 0;
1402 xmlXPathDebugObjTotalRange = 0;
1403 xmlXPathDebugObjTotalLocset = 0;
1404 xmlXPathDebugObjTotalUsers = 0;
1405 xmlXPathDebugObjTotalXSLTTree = 0;
1406 xmlXPathDebugObjTotalAll = 0;
1407
1408 xmlXPathDebugObjMaxUndefined = 0;
1409 xmlXPathDebugObjMaxNodeset = 0;
1410 xmlXPathDebugObjMaxBool = 0;
1411 xmlXPathDebugObjMaxNumber = 0;
1412 xmlXPathDebugObjMaxString = 0;
1413 xmlXPathDebugObjMaxPoint = 0;
1414 xmlXPathDebugObjMaxRange = 0;
1415 xmlXPathDebugObjMaxLocset = 0;
1416 xmlXPathDebugObjMaxUsers = 0;
1417 xmlXPathDebugObjMaxXSLTTree = 0;
1418 xmlXPathDebugObjMaxAll = 0;
1419
1420}
1421
1422static void
1423xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1424 xmlXPathObjectType objType)
1425{
1426 int isCached = 0;
1427
1428 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001429 if (ctxt->cache != NULL) {
1430 xmlXPathContextCachePtr cache =
1431 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001432
1433 isCached = 1;
1434
1435 cache->dbgReusedAll++;
1436 switch (objType) {
1437 case XPATH_UNDEFINED:
1438 cache->dbgReusedUndefined++;
1439 break;
1440 case XPATH_NODESET:
1441 cache->dbgReusedNodeset++;
1442 break;
1443 case XPATH_BOOLEAN:
1444 cache->dbgReusedBool++;
1445 break;
1446 case XPATH_NUMBER:
1447 cache->dbgReusedNumber++;
1448 break;
1449 case XPATH_STRING:
1450 cache->dbgReusedString++;
1451 break;
1452 case XPATH_POINT:
1453 cache->dbgReusedPoint++;
1454 break;
1455 case XPATH_RANGE:
1456 cache->dbgReusedRange++;
1457 break;
1458 case XPATH_LOCATIONSET:
1459 cache->dbgReusedLocset++;
1460 break;
1461 case XPATH_USERS:
1462 cache->dbgReusedUsers++;
1463 break;
1464 case XPATH_XSLT_TREE:
1465 cache->dbgReusedXSLTTree++;
1466 break;
1467 default:
1468 break;
1469 }
1470 }
1471 }
1472
1473 switch (objType) {
1474 case XPATH_UNDEFINED:
1475 if (! isCached)
1476 xmlXPathDebugObjTotalUndefined++;
1477 xmlXPathDebugObjCounterUndefined++;
1478 if (xmlXPathDebugObjCounterUndefined >
1479 xmlXPathDebugObjMaxUndefined)
1480 xmlXPathDebugObjMaxUndefined =
1481 xmlXPathDebugObjCounterUndefined;
1482 break;
1483 case XPATH_NODESET:
1484 if (! isCached)
1485 xmlXPathDebugObjTotalNodeset++;
1486 xmlXPathDebugObjCounterNodeset++;
1487 if (xmlXPathDebugObjCounterNodeset >
1488 xmlXPathDebugObjMaxNodeset)
1489 xmlXPathDebugObjMaxNodeset =
1490 xmlXPathDebugObjCounterNodeset;
1491 break;
1492 case XPATH_BOOLEAN:
1493 if (! isCached)
1494 xmlXPathDebugObjTotalBool++;
1495 xmlXPathDebugObjCounterBool++;
1496 if (xmlXPathDebugObjCounterBool >
1497 xmlXPathDebugObjMaxBool)
1498 xmlXPathDebugObjMaxBool =
1499 xmlXPathDebugObjCounterBool;
1500 break;
1501 case XPATH_NUMBER:
1502 if (! isCached)
1503 xmlXPathDebugObjTotalNumber++;
1504 xmlXPathDebugObjCounterNumber++;
1505 if (xmlXPathDebugObjCounterNumber >
1506 xmlXPathDebugObjMaxNumber)
1507 xmlXPathDebugObjMaxNumber =
1508 xmlXPathDebugObjCounterNumber;
1509 break;
1510 case XPATH_STRING:
1511 if (! isCached)
1512 xmlXPathDebugObjTotalString++;
1513 xmlXPathDebugObjCounterString++;
1514 if (xmlXPathDebugObjCounterString >
1515 xmlXPathDebugObjMaxString)
1516 xmlXPathDebugObjMaxString =
1517 xmlXPathDebugObjCounterString;
1518 break;
1519 case XPATH_POINT:
1520 if (! isCached)
1521 xmlXPathDebugObjTotalPoint++;
1522 xmlXPathDebugObjCounterPoint++;
1523 if (xmlXPathDebugObjCounterPoint >
1524 xmlXPathDebugObjMaxPoint)
1525 xmlXPathDebugObjMaxPoint =
1526 xmlXPathDebugObjCounterPoint;
1527 break;
1528 case XPATH_RANGE:
1529 if (! isCached)
1530 xmlXPathDebugObjTotalRange++;
1531 xmlXPathDebugObjCounterRange++;
1532 if (xmlXPathDebugObjCounterRange >
1533 xmlXPathDebugObjMaxRange)
1534 xmlXPathDebugObjMaxRange =
1535 xmlXPathDebugObjCounterRange;
1536 break;
1537 case XPATH_LOCATIONSET:
1538 if (! isCached)
1539 xmlXPathDebugObjTotalLocset++;
1540 xmlXPathDebugObjCounterLocset++;
1541 if (xmlXPathDebugObjCounterLocset >
1542 xmlXPathDebugObjMaxLocset)
1543 xmlXPathDebugObjMaxLocset =
1544 xmlXPathDebugObjCounterLocset;
1545 break;
1546 case XPATH_USERS:
1547 if (! isCached)
1548 xmlXPathDebugObjTotalUsers++;
1549 xmlXPathDebugObjCounterUsers++;
1550 if (xmlXPathDebugObjCounterUsers >
1551 xmlXPathDebugObjMaxUsers)
1552 xmlXPathDebugObjMaxUsers =
1553 xmlXPathDebugObjCounterUsers;
1554 break;
1555 case XPATH_XSLT_TREE:
1556 if (! isCached)
1557 xmlXPathDebugObjTotalXSLTTree++;
1558 xmlXPathDebugObjCounterXSLTTree++;
1559 if (xmlXPathDebugObjCounterXSLTTree >
1560 xmlXPathDebugObjMaxXSLTTree)
1561 xmlXPathDebugObjMaxXSLTTree =
1562 xmlXPathDebugObjCounterXSLTTree;
1563 break;
1564 default:
1565 break;
1566 }
1567 if (! isCached)
1568 xmlXPathDebugObjTotalAll++;
1569 xmlXPathDebugObjCounterAll++;
1570 if (xmlXPathDebugObjCounterAll >
1571 xmlXPathDebugObjMaxAll)
1572 xmlXPathDebugObjMaxAll =
1573 xmlXPathDebugObjCounterAll;
1574}
1575
1576static void
1577xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1578 xmlXPathObjectType objType)
1579{
1580 int isCached = 0;
1581
1582 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001583 if (ctxt->cache != NULL) {
1584 xmlXPathContextCachePtr cache =
1585 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001586
1587 isCached = 1;
1588
1589 cache->dbgCachedAll++;
1590 switch (objType) {
1591 case XPATH_UNDEFINED:
1592 cache->dbgCachedUndefined++;
1593 break;
1594 case XPATH_NODESET:
1595 cache->dbgCachedNodeset++;
1596 break;
1597 case XPATH_BOOLEAN:
1598 cache->dbgCachedBool++;
1599 break;
1600 case XPATH_NUMBER:
1601 cache->dbgCachedNumber++;
1602 break;
1603 case XPATH_STRING:
1604 cache->dbgCachedString++;
1605 break;
1606 case XPATH_POINT:
1607 cache->dbgCachedPoint++;
1608 break;
1609 case XPATH_RANGE:
1610 cache->dbgCachedRange++;
1611 break;
1612 case XPATH_LOCATIONSET:
1613 cache->dbgCachedLocset++;
1614 break;
1615 case XPATH_USERS:
1616 cache->dbgCachedUsers++;
1617 break;
1618 case XPATH_XSLT_TREE:
1619 cache->dbgCachedXSLTTree++;
1620 break;
1621 default:
1622 break;
1623 }
1624
1625 }
1626 }
1627 switch (objType) {
1628 case XPATH_UNDEFINED:
1629 xmlXPathDebugObjCounterUndefined--;
1630 break;
1631 case XPATH_NODESET:
1632 xmlXPathDebugObjCounterNodeset--;
1633 break;
1634 case XPATH_BOOLEAN:
1635 xmlXPathDebugObjCounterBool--;
1636 break;
1637 case XPATH_NUMBER:
1638 xmlXPathDebugObjCounterNumber--;
1639 break;
1640 case XPATH_STRING:
1641 xmlXPathDebugObjCounterString--;
1642 break;
1643 case XPATH_POINT:
1644 xmlXPathDebugObjCounterPoint--;
1645 break;
1646 case XPATH_RANGE:
1647 xmlXPathDebugObjCounterRange--;
1648 break;
1649 case XPATH_LOCATIONSET:
1650 xmlXPathDebugObjCounterLocset--;
1651 break;
1652 case XPATH_USERS:
1653 xmlXPathDebugObjCounterUsers--;
1654 break;
1655 case XPATH_XSLT_TREE:
1656 xmlXPathDebugObjCounterXSLTTree--;
1657 break;
1658 default:
1659 break;
1660 }
1661 xmlXPathDebugObjCounterAll--;
1662}
1663
1664/* REVISIT TODO: Make this static when committing */
1665static void
1666xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
1667{
1668 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
1669 reqXSLTTree, reqUndefined;
1670 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
1671 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
1672 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
1673 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
1674 int leftObjs = xmlXPathDebugObjCounterAll;
1675
1676 reqAll = xmlXPathDebugObjTotalAll;
1677 reqNodeset = xmlXPathDebugObjTotalNodeset;
1678 reqString = xmlXPathDebugObjTotalString;
1679 reqBool = xmlXPathDebugObjTotalBool;
1680 reqNumber = xmlXPathDebugObjTotalNumber;
1681 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
1682 reqUndefined = xmlXPathDebugObjTotalUndefined;
1683
1684 printf("# XPath object usage:\n");
1685
1686 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001687 if (ctxt->cache != NULL) {
1688 xmlXPathContextCachePtr cache =
1689 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001690
1691 reAll = cache->dbgReusedAll;
1692 reqAll += reAll;
1693 reNodeset = cache->dbgReusedNodeset;
1694 reqNodeset += reNodeset;
1695 reString = cache->dbgReusedString;
1696 reqString += reString;
1697 reBool = cache->dbgReusedBool;
1698 reqBool += reBool;
1699 reNumber = cache->dbgReusedNumber;
1700 reqNumber += reNumber;
1701 reXSLTTree = cache->dbgReusedXSLTTree;
1702 reqXSLTTree += reXSLTTree;
1703 reUndefined = cache->dbgReusedUndefined;
1704 reqUndefined += reUndefined;
1705
1706 caAll = cache->dbgCachedAll;
1707 caBool = cache->dbgCachedBool;
1708 caNodeset = cache->dbgCachedNodeset;
1709 caString = cache->dbgCachedString;
1710 caNumber = cache->dbgCachedNumber;
1711 caXSLTTree = cache->dbgCachedXSLTTree;
1712 caUndefined = cache->dbgCachedUndefined;
1713
1714 if (cache->nodesetObjs)
1715 leftObjs -= cache->nodesetObjs->number;
1716 if (cache->stringObjs)
1717 leftObjs -= cache->stringObjs->number;
1718 if (cache->booleanObjs)
1719 leftObjs -= cache->booleanObjs->number;
1720 if (cache->numberObjs)
1721 leftObjs -= cache->numberObjs->number;
1722 if (cache->miscObjs)
1723 leftObjs -= cache->miscObjs->number;
1724 }
1725 }
1726
1727 printf("# all\n");
1728 printf("# total : %d\n", reqAll);
1729 printf("# left : %d\n", leftObjs);
1730 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
1731 printf("# reused : %d\n", reAll);
1732 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
1733
1734 printf("# node-sets\n");
1735 printf("# total : %d\n", reqNodeset);
1736 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
1737 printf("# reused : %d\n", reNodeset);
1738 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
1739
1740 printf("# strings\n");
1741 printf("# total : %d\n", reqString);
1742 printf("# created: %d\n", xmlXPathDebugObjTotalString);
1743 printf("# reused : %d\n", reString);
1744 printf("# max : %d\n", xmlXPathDebugObjMaxString);
1745
1746 printf("# booleans\n");
1747 printf("# total : %d\n", reqBool);
1748 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
1749 printf("# reused : %d\n", reBool);
1750 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
1751
1752 printf("# numbers\n");
1753 printf("# total : %d\n", reqNumber);
1754 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
1755 printf("# reused : %d\n", reNumber);
1756 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
1757
1758 printf("# XSLT result tree fragments\n");
1759 printf("# total : %d\n", reqXSLTTree);
1760 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
1761 printf("# reused : %d\n", reXSLTTree);
1762 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
1763
1764 printf("# undefined\n");
1765 printf("# total : %d\n", reqUndefined);
1766 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
1767 printf("# reused : %d\n", reUndefined);
1768 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
1769
1770}
1771
1772#endif /* XP_DEBUG_OBJ_USAGE */
1773
Daniel Veillard017b1082001-06-21 11:20:21 +00001774#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001775
1776/************************************************************************
1777 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001778 * XPath object caching *
1779 * *
1780 ************************************************************************/
1781
1782/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001783 * xmlXPathNewCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001784 *
1785 * Create a new object cache
1786 *
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001787 * Returns the xmlXPathCache just allocated.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001788 */
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001789static xmlXPathContextCachePtr
1790xmlXPathNewCache(void)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001791{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001792 xmlXPathContextCachePtr ret;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001793
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001794 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001795 if (ret == NULL) {
1796 xmlXPathErrMemory(NULL, "creating object cache\n");
1797 return(NULL);
1798 }
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001799 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001800 ret->maxNodeset = 100;
1801 ret->maxString = 100;
1802 ret->maxBoolean = 100;
1803 ret->maxNumber = 100;
1804 ret->maxMisc = 100;
1805 return(ret);
1806}
1807
1808static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001809xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001810{
1811 int i;
1812 xmlXPathObjectPtr obj;
1813
1814 if (list == NULL)
1815 return;
1816
1817 for (i = 0; i < list->number; i++) {
1818 obj = list->items[i];
1819 /*
1820 * Note that it is already assured that we don't need to
1821 * look out for namespace nodes in the node-set.
1822 */
1823 if (obj->nodesetval != NULL) {
1824 if (obj->nodesetval->nodeTab != NULL)
1825 xmlFree(obj->nodesetval->nodeTab);
1826 xmlFree(obj->nodesetval);
1827 }
1828 xmlFree(obj);
1829#ifdef XP_DEBUG_OBJ_USAGE
1830 xmlXPathDebugObjCounterAll--;
1831#endif
1832 }
1833 xmlPointerListFree(list);
1834}
1835
1836static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001837xmlXPathFreeCache(xmlXPathContextCachePtr cache)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001838{
1839 if (cache == NULL)
1840 return;
1841 if (cache->nodesetObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001842 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001843 if (cache->stringObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001844 xmlXPathCacheFreeObjectList(cache->stringObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001845 if (cache->booleanObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001846 xmlXPathCacheFreeObjectList(cache->booleanObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001847 if (cache->numberObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001848 xmlXPathCacheFreeObjectList(cache->numberObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001849 if (cache->miscObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001850 xmlXPathCacheFreeObjectList(cache->miscObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001851 xmlFree(cache);
1852}
1853
1854/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001855 * xmlXPathContextSetCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001856 *
1857 * @ctxt: the XPath context
1858 * @active: enables/disables (creates/frees) the cache
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001859 * @value: a value with semantics dependant on @options
1860 * @options: options (currently only the value 0 is used)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001861 *
1862 * Creates/frees an object cache on the XPath context.
1863 * If activates XPath objects (xmlXPathObject) will be cached internally
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001864 * to be reused.
1865 * @options:
1866 * 0: This will set the XPath object caching:
1867 * @value:
1868 * This will set the maximum number of XPath objects
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001869 * to be cached per slot
1870 * There are 5 slots for: node-set, string, number, boolean, and
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001871 * misc objects. Use <0 for the default number (100).
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001872 * Other values for @options have currently no effect.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001873 *
1874 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1875 */
1876int
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001877xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1878 int active,
1879 int value,
1880 int options)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001881{
1882 if (ctxt == NULL)
1883 return(-1);
1884 if (active) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001885 xmlXPathContextCachePtr cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001886
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001887 if (ctxt->cache == NULL) {
1888 ctxt->cache = xmlXPathNewCache();
1889 if (ctxt->cache == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001890 return(-1);
1891 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001892 cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001893 if (options == 0) {
1894 if (value < 0)
1895 value = 100;
1896 cache->maxNodeset = value;
1897 cache->maxString = value;
1898 cache->maxNumber = value;
1899 cache->maxBoolean = value;
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001900 cache->maxMisc = value;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001901 }
1902 } else if (ctxt->cache != NULL) {
1903 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1904 ctxt->cache = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001905 }
1906 return(0);
1907}
1908
1909/**
1910 * xmlXPathCacheWrapNodeSet:
1911 * @ctxt: the XPath context
1912 * @val: the NodePtr value
1913 *
1914 * This is the cached version of xmlXPathWrapNodeSet().
1915 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1916 *
1917 * Returns the created or reused object.
1918 */
1919static xmlXPathObjectPtr
1920xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
1921{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001922 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1923 xmlXPathContextCachePtr cache =
1924 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001925
1926 if ((cache->miscObjs != NULL) &&
1927 (cache->miscObjs->number != 0))
1928 {
1929 xmlXPathObjectPtr ret;
1930
1931 ret = (xmlXPathObjectPtr)
1932 cache->miscObjs->items[--cache->miscObjs->number];
1933 ret->type = XPATH_NODESET;
1934 ret->nodesetval = val;
1935#ifdef XP_DEBUG_OBJ_USAGE
1936 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
1937#endif
1938 return(ret);
1939 }
1940 }
1941
1942 return(xmlXPathWrapNodeSet(val));
1943
1944}
1945
1946/**
1947 * xmlXPathCacheWrapString:
1948 * @ctxt: the XPath context
1949 * @val: the xmlChar * value
1950 *
1951 * This is the cached version of xmlXPathWrapString().
1952 * Wraps the @val string into an XPath object.
1953 *
1954 * Returns the created or reused object.
1955 */
1956static xmlXPathObjectPtr
1957xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
1958{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001959 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1960 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001961
1962 if ((cache->stringObjs != NULL) &&
1963 (cache->stringObjs->number != 0))
1964 {
1965
1966 xmlXPathObjectPtr ret;
1967
1968 ret = (xmlXPathObjectPtr)
1969 cache->stringObjs->items[--cache->stringObjs->number];
1970 ret->type = XPATH_STRING;
1971 ret->stringval = val;
1972#ifdef XP_DEBUG_OBJ_USAGE
1973 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1974#endif
1975 return(ret);
1976 } else if ((cache->miscObjs != NULL) &&
1977 (cache->miscObjs->number != 0))
1978 {
1979 xmlXPathObjectPtr ret;
1980 /*
1981 * Fallback to misc-cache.
1982 */
1983 ret = (xmlXPathObjectPtr)
1984 cache->miscObjs->items[--cache->miscObjs->number];
1985
1986 ret->type = XPATH_STRING;
1987 ret->stringval = val;
1988#ifdef XP_DEBUG_OBJ_USAGE
1989 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1990#endif
1991 return(ret);
1992 }
1993 }
1994 return(xmlXPathWrapString(val));
1995}
1996
1997/**
1998 * xmlXPathCacheNewNodeSet:
1999 * @ctxt: the XPath context
2000 * @val: the NodePtr value
2001 *
2002 * This is the cached version of xmlXPathNewNodeSet().
2003 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2004 * it with the single Node @val
2005 *
2006 * Returns the created or reused object.
2007 */
2008static xmlXPathObjectPtr
2009xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2010{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002011 if ((ctxt != NULL) && (ctxt->cache)) {
2012 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002013
2014 if ((cache->nodesetObjs != NULL) &&
2015 (cache->nodesetObjs->number != 0))
2016 {
2017 xmlXPathObjectPtr ret;
2018 /*
2019 * Use the nodset-cache.
2020 */
2021 ret = (xmlXPathObjectPtr)
2022 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2023 ret->type = XPATH_NODESET;
2024 ret->boolval = 0;
2025 if (val) {
2026 if ((ret->nodesetval->nodeMax == 0) ||
2027 (val->type == XML_NAMESPACE_DECL))
2028 {
2029 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2030 } else {
2031 ret->nodesetval->nodeTab[0] = val;
2032 ret->nodesetval->nodeNr = 1;
2033 }
2034 }
2035#ifdef XP_DEBUG_OBJ_USAGE
2036 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2037#endif
2038 return(ret);
2039 } else if ((cache->miscObjs != NULL) &&
2040 (cache->miscObjs->number != 0))
2041 {
2042 xmlXPathObjectPtr ret;
2043 /*
2044 * Fallback to misc-cache.
2045 */
2046
2047 ret = (xmlXPathObjectPtr)
2048 cache->miscObjs->items[--cache->miscObjs->number];
2049
2050 ret->type = XPATH_NODESET;
2051 ret->boolval = 0;
2052 ret->nodesetval = xmlXPathNodeSetCreate(val);
2053#ifdef XP_DEBUG_OBJ_USAGE
2054 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2055#endif
2056 return(ret);
2057 }
2058 }
2059 return(xmlXPathNewNodeSet(val));
2060}
2061
2062/**
2063 * xmlXPathCacheNewCString:
2064 * @ctxt: the XPath context
2065 * @val: the char * value
2066 *
2067 * This is the cached version of xmlXPathNewCString().
2068 * Acquire an xmlXPathObjectPtr of type string and of value @val
2069 *
2070 * Returns the created or reused object.
2071 */
2072static xmlXPathObjectPtr
2073xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2074{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002075 if ((ctxt != NULL) && (ctxt->cache)) {
2076 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002077
2078 if ((cache->stringObjs != NULL) &&
2079 (cache->stringObjs->number != 0))
2080 {
2081 xmlXPathObjectPtr ret;
2082
2083 ret = (xmlXPathObjectPtr)
2084 cache->stringObjs->items[--cache->stringObjs->number];
2085
2086 ret->type = XPATH_STRING;
2087 ret->stringval = xmlStrdup(BAD_CAST val);
2088#ifdef XP_DEBUG_OBJ_USAGE
2089 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2090#endif
2091 return(ret);
2092 } else if ((cache->miscObjs != NULL) &&
2093 (cache->miscObjs->number != 0))
2094 {
2095 xmlXPathObjectPtr ret;
2096
2097 ret = (xmlXPathObjectPtr)
2098 cache->miscObjs->items[--cache->miscObjs->number];
2099
2100 ret->type = XPATH_STRING;
2101 ret->stringval = xmlStrdup(BAD_CAST val);
2102#ifdef XP_DEBUG_OBJ_USAGE
2103 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2104#endif
2105 return(ret);
2106 }
2107 }
2108 return(xmlXPathNewCString(val));
2109}
2110
2111/**
2112 * xmlXPathCacheNewString:
2113 * @ctxt: the XPath context
2114 * @val: the xmlChar * value
2115 *
2116 * This is the cached version of xmlXPathNewString().
2117 * Acquire an xmlXPathObjectPtr of type string and of value @val
2118 *
2119 * Returns the created or reused object.
2120 */
2121static xmlXPathObjectPtr
2122xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2123{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002124 if ((ctxt != NULL) && (ctxt->cache)) {
2125 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002126
2127 if ((cache->stringObjs != NULL) &&
2128 (cache->stringObjs->number != 0))
2129 {
2130 xmlXPathObjectPtr ret;
2131
2132 ret = (xmlXPathObjectPtr)
2133 cache->stringObjs->items[--cache->stringObjs->number];
2134 ret->type = XPATH_STRING;
2135 if (val != NULL)
2136 ret->stringval = xmlStrdup(val);
2137 else
2138 ret->stringval = xmlStrdup((const xmlChar *)"");
2139#ifdef XP_DEBUG_OBJ_USAGE
2140 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2141#endif
2142 return(ret);
2143 } else if ((cache->miscObjs != NULL) &&
2144 (cache->miscObjs->number != 0))
2145 {
2146 xmlXPathObjectPtr ret;
2147
2148 ret = (xmlXPathObjectPtr)
2149 cache->miscObjs->items[--cache->miscObjs->number];
2150
2151 ret->type = XPATH_STRING;
2152 if (val != NULL)
2153 ret->stringval = xmlStrdup(val);
2154 else
2155 ret->stringval = xmlStrdup((const xmlChar *)"");
2156#ifdef XP_DEBUG_OBJ_USAGE
2157 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2158#endif
2159 return(ret);
2160 }
2161 }
2162 return(xmlXPathNewString(val));
2163}
2164
2165/**
2166 * xmlXPathCacheNewBoolean:
2167 * @ctxt: the XPath context
2168 * @val: the boolean value
2169 *
2170 * This is the cached version of xmlXPathNewBoolean().
2171 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2172 *
2173 * Returns the created or reused object.
2174 */
2175static xmlXPathObjectPtr
2176xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2177{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002178 if ((ctxt != NULL) && (ctxt->cache)) {
2179 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002180
2181 if ((cache->booleanObjs != NULL) &&
2182 (cache->booleanObjs->number != 0))
2183 {
2184 xmlXPathObjectPtr ret;
2185
2186 ret = (xmlXPathObjectPtr)
2187 cache->booleanObjs->items[--cache->booleanObjs->number];
2188 ret->type = XPATH_BOOLEAN;
2189 ret->boolval = (val != 0);
2190#ifdef XP_DEBUG_OBJ_USAGE
2191 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2192#endif
2193 return(ret);
2194 } else if ((cache->miscObjs != NULL) &&
2195 (cache->miscObjs->number != 0))
2196 {
2197 xmlXPathObjectPtr ret;
2198
2199 ret = (xmlXPathObjectPtr)
2200 cache->miscObjs->items[--cache->miscObjs->number];
2201
2202 ret->type = XPATH_BOOLEAN;
2203 ret->boolval = (val != 0);
2204#ifdef XP_DEBUG_OBJ_USAGE
2205 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2206#endif
2207 return(ret);
2208 }
2209 }
2210 return(xmlXPathNewBoolean(val));
2211}
2212
2213/**
2214 * xmlXPathCacheNewFloat:
2215 * @ctxt: the XPath context
2216 * @val: the double value
2217 *
2218 * This is the cached version of xmlXPathNewFloat().
2219 * Acquires an xmlXPathObjectPtr of type double and of value @val
2220 *
2221 * Returns the created or reused object.
2222 */
2223static xmlXPathObjectPtr
2224xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2225{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002226 if ((ctxt != NULL) && (ctxt->cache)) {
2227 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002228
2229 if ((cache->numberObjs != NULL) &&
2230 (cache->numberObjs->number != 0))
2231 {
2232 xmlXPathObjectPtr ret;
2233
2234 ret = (xmlXPathObjectPtr)
2235 cache->numberObjs->items[--cache->numberObjs->number];
2236 ret->type = XPATH_NUMBER;
2237 ret->floatval = val;
2238#ifdef XP_DEBUG_OBJ_USAGE
2239 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2240#endif
2241 return(ret);
2242 } else if ((cache->miscObjs != NULL) &&
2243 (cache->miscObjs->number != 0))
2244 {
2245 xmlXPathObjectPtr ret;
2246
2247 ret = (xmlXPathObjectPtr)
2248 cache->miscObjs->items[--cache->miscObjs->number];
2249
2250 ret->type = XPATH_NUMBER;
2251 ret->floatval = val;
2252#ifdef XP_DEBUG_OBJ_USAGE
2253 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2254#endif
2255 return(ret);
2256 }
2257 }
2258 return(xmlXPathNewFloat(val));
2259}
2260
2261/**
2262 * xmlXPathCacheConvertString:
2263 * @ctxt: the XPath context
2264 * @val: an XPath object
2265 *
2266 * This is the cached version of xmlXPathConvertString().
2267 * Converts an existing object to its string() equivalent
2268 *
2269 * Returns a created or reused object, the old one is freed (cached)
2270 * (or the operation is done directly on @val)
2271 */
2272
2273static xmlXPathObjectPtr
2274xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2275 xmlChar *res = NULL;
2276
2277 if (val == NULL)
2278 return(xmlXPathCacheNewCString(ctxt, ""));
2279
2280 switch (val->type) {
2281 case XPATH_UNDEFINED:
2282#ifdef DEBUG_EXPR
2283 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2284#endif
2285 break;
2286 case XPATH_NODESET:
2287 case XPATH_XSLT_TREE:
2288 res = xmlXPathCastNodeSetToString(val->nodesetval);
2289 break;
2290 case XPATH_STRING:
2291 return(val);
2292 case XPATH_BOOLEAN:
2293 res = xmlXPathCastBooleanToString(val->boolval);
2294 break;
2295 case XPATH_NUMBER:
2296 res = xmlXPathCastNumberToString(val->floatval);
2297 break;
2298 case XPATH_USERS:
2299 case XPATH_POINT:
2300 case XPATH_RANGE:
2301 case XPATH_LOCATIONSET:
2302 TODO;
2303 break;
2304 }
2305 xmlXPathReleaseObject(ctxt, val);
2306 if (res == NULL)
2307 return(xmlXPathCacheNewCString(ctxt, ""));
2308 return(xmlXPathCacheWrapString(ctxt, res));
2309}
2310
2311/**
2312 * xmlXPathCacheObjectCopy:
2313 * @ctxt: the XPath context
2314 * @val: the original object
2315 *
2316 * This is the cached version of xmlXPathObjectCopy().
2317 * Acquire a copy of a given object
2318 *
2319 * Returns a created or reused created object.
2320 */
2321static xmlXPathObjectPtr
2322xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2323{
2324 if (val == NULL)
2325 return(NULL);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002326
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002327 if (XP_HAS_CACHE(ctxt)) {
2328 switch (val->type) {
2329 case XPATH_NODESET:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002330 return(xmlXPathCacheWrapNodeSet(ctxt,
2331 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002332 case XPATH_STRING:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002333 return(xmlXPathCacheNewString(ctxt, val->stringval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002334 case XPATH_BOOLEAN:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002335 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002336 case XPATH_NUMBER:
2337 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2338 default:
2339 break;
2340 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002341 }
2342 return(xmlXPathObjectCopy(val));
2343}
2344
2345/**
2346 * xmlXPathCacheConvertBoolean:
2347 * @ctxt: the XPath context
2348 * @val: an XPath object
2349 *
2350 * This is the cached version of xmlXPathConvertBoolean().
2351 * Converts an existing object to its boolean() equivalent
2352 *
2353 * Returns a created or reused object, the old one is freed (or the operation
2354 * is done directly on @val)
2355 */
2356static xmlXPathObjectPtr
2357xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2358 xmlXPathObjectPtr ret;
2359
2360 if (val == NULL)
2361 return(xmlXPathCacheNewBoolean(ctxt, 0));
2362 if (val->type == XPATH_BOOLEAN)
2363 return(val);
2364 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2365 xmlXPathReleaseObject(ctxt, val);
2366 return(ret);
2367}
2368
2369/**
2370 * xmlXPathCacheConvertNumber:
2371 * @ctxt: the XPath context
2372 * @val: an XPath object
2373 *
2374 * This is the cached version of xmlXPathConvertNumber().
2375 * Converts an existing object to its number() equivalent
2376 *
2377 * Returns a created or reused object, the old one is freed (or the operation
2378 * is done directly on @val)
2379 */
2380static xmlXPathObjectPtr
2381xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2382 xmlXPathObjectPtr ret;
2383
2384 if (val == NULL)
2385 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2386 if (val->type == XPATH_NUMBER)
2387 return(val);
2388 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2389 xmlXPathReleaseObject(ctxt, val);
2390 return(ret);
2391}
2392
2393/************************************************************************
2394 * *
Owen Taylor3473f882001-02-23 17:55:21 +00002395 * Parser stacks related functions and macros *
2396 * *
2397 ************************************************************************/
2398
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002399/**
2400 * valuePop:
2401 * @ctxt: an XPath evaluation context
2402 *
2403 * Pops the top XPath object from the value stack
2404 *
2405 * Returns the XPath object just removed
2406 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002407xmlXPathObjectPtr
Daniel Veillard1c732d22002-11-30 11:22:59 +00002408valuePop(xmlXPathParserContextPtr ctxt)
2409{
2410 xmlXPathObjectPtr ret;
2411
Daniel Veillarda82b1822004-11-08 16:24:57 +00002412 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
Daniel Veillard24505b02005-07-28 23:49:35 +00002413 return (NULL);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002414 ctxt->valueNr--;
2415 if (ctxt->valueNr > 0)
2416 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2417 else
2418 ctxt->value = NULL;
2419 ret = ctxt->valueTab[ctxt->valueNr];
Daniel Veillard24505b02005-07-28 23:49:35 +00002420 ctxt->valueTab[ctxt->valueNr] = NULL;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002421 return (ret);
2422}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002423/**
2424 * valuePush:
2425 * @ctxt: an XPath evaluation context
2426 * @value: the XPath object
2427 *
2428 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002429 *
2430 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002431 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002432int
Daniel Veillard1c732d22002-11-30 11:22:59 +00002433valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2434{
Daniel Veillarda82b1822004-11-08 16:24:57 +00002435 if ((ctxt == NULL) || (value == NULL)) return(-1);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002436 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002437 xmlXPathObjectPtr *tmp;
2438
2439 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2440 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00002441 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002442 if (tmp == NULL) {
Daniel Veillard1c732d22002-11-30 11:22:59 +00002443 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
2444 return (0);
2445 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002446 ctxt->valueMax *= 2;
2447 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002448 }
2449 ctxt->valueTab[ctxt->valueNr] = value;
2450 ctxt->value = value;
2451 return (ctxt->valueNr++);
2452}
Owen Taylor3473f882001-02-23 17:55:21 +00002453
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002454/**
2455 * xmlXPathPopBoolean:
2456 * @ctxt: an XPath parser context
2457 *
2458 * Pops a boolean from the stack, handling conversion if needed.
2459 * Check error with #xmlXPathCheckError.
2460 *
2461 * Returns the boolean
2462 */
2463int
2464xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2465 xmlXPathObjectPtr obj;
2466 int ret;
2467
2468 obj = valuePop(ctxt);
2469 if (obj == NULL) {
2470 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2471 return(0);
2472 }
William M. Brack08171912003-12-29 02:52:11 +00002473 if (obj->type != XPATH_BOOLEAN)
2474 ret = xmlXPathCastToBoolean(obj);
2475 else
2476 ret = obj->boolval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002477 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002478 return(ret);
2479}
2480
2481/**
2482 * xmlXPathPopNumber:
2483 * @ctxt: an XPath parser context
2484 *
2485 * Pops a number from the stack, handling conversion if needed.
2486 * Check error with #xmlXPathCheckError.
2487 *
2488 * Returns the number
2489 */
2490double
2491xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2492 xmlXPathObjectPtr obj;
2493 double ret;
2494
2495 obj = valuePop(ctxt);
2496 if (obj == NULL) {
2497 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2498 return(0);
2499 }
William M. Brack08171912003-12-29 02:52:11 +00002500 if (obj->type != XPATH_NUMBER)
2501 ret = xmlXPathCastToNumber(obj);
2502 else
2503 ret = obj->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002504 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002505 return(ret);
2506}
2507
2508/**
2509 * xmlXPathPopString:
2510 * @ctxt: an XPath parser context
2511 *
2512 * Pops a string from the stack, handling conversion if needed.
2513 * Check error with #xmlXPathCheckError.
2514 *
2515 * Returns the string
2516 */
2517xmlChar *
2518xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2519 xmlXPathObjectPtr obj;
2520 xmlChar * ret;
2521
2522 obj = valuePop(ctxt);
2523 if (obj == NULL) {
2524 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2525 return(NULL);
2526 }
William M. Brack08171912003-12-29 02:52:11 +00002527 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002528 /* TODO: needs refactoring somewhere else */
2529 if (obj->stringval == ret)
2530 obj->stringval = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002531 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002532 return(ret);
2533}
2534
2535/**
2536 * xmlXPathPopNodeSet:
2537 * @ctxt: an XPath parser context
2538 *
2539 * Pops a node-set from the stack, handling conversion if needed.
2540 * Check error with #xmlXPathCheckError.
2541 *
2542 * Returns the node-set
2543 */
2544xmlNodeSetPtr
2545xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2546 xmlXPathObjectPtr obj;
2547 xmlNodeSetPtr ret;
2548
Daniel Veillardf2a36f92004-11-08 17:55:01 +00002549 if (ctxt == NULL) return(NULL);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002550 if (ctxt->value == NULL) {
2551 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2552 return(NULL);
2553 }
2554 if (!xmlXPathStackIsNodeSet(ctxt)) {
2555 xmlXPathSetTypeError(ctxt);
2556 return(NULL);
2557 }
2558 obj = valuePop(ctxt);
2559 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00002560#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00002561 /* to fix memory leak of not clearing obj->user */
2562 if (obj->boolval && obj->user != NULL)
2563 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00002564#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002565 obj->nodesetval = NULL;
2566 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002567 return(ret);
2568}
2569
2570/**
2571 * xmlXPathPopExternal:
2572 * @ctxt: an XPath parser context
2573 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002574 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002575 * Check error with #xmlXPathCheckError.
2576 *
2577 * Returns the object
2578 */
2579void *
2580xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2581 xmlXPathObjectPtr obj;
2582 void * ret;
2583
Daniel Veillarda82b1822004-11-08 16:24:57 +00002584 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002585 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2586 return(NULL);
2587 }
2588 if (ctxt->value->type != XPATH_USERS) {
2589 xmlXPathSetTypeError(ctxt);
2590 return(NULL);
2591 }
2592 obj = valuePop(ctxt);
2593 ret = obj->user;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002594 obj->user = NULL;
2595 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002596 return(ret);
2597}
2598
Owen Taylor3473f882001-02-23 17:55:21 +00002599/*
2600 * Macros for accessing the content. Those should be used only by the parser,
2601 * and not exported.
2602 *
2603 * Dirty macros, i.e. one need to make assumption on the context to use them
2604 *
2605 * CUR_PTR return the current pointer to the xmlChar to be parsed.
2606 * CUR returns the current xmlChar value, i.e. a 8 bit value
2607 * in ISO-Latin or UTF-8.
2608 * This should be used internally by the parser
2609 * only to compare to ASCII values otherwise it would break when
2610 * running with UTF-8 encoding.
2611 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
2612 * to compare on ASCII based substring.
2613 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2614 * strings within the parser.
2615 * CURRENT Returns the current char value, with the full decoding of
2616 * UTF-8 if we are using this mode. It returns an int.
2617 * NEXT Skip to the next character, this does the proper decoding
2618 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
2619 * It returns the pointer to the current xmlChar.
2620 */
2621
2622#define CUR (*ctxt->cur)
2623#define SKIP(val) ctxt->cur += (val)
2624#define NXT(val) ctxt->cur[(val)]
2625#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00002626#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2627
2628#define COPY_BUF(l,b,i,v) \
2629 if (l == 1) b[i++] = (xmlChar) v; \
2630 else i += xmlCopyChar(l,&b[i],v)
2631
2632#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00002633
2634#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00002635 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00002636
2637#define CURRENT (*ctxt->cur)
2638#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
2639
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002640
2641#ifndef DBL_DIG
2642#define DBL_DIG 16
2643#endif
2644#ifndef DBL_EPSILON
2645#define DBL_EPSILON 1E-9
2646#endif
2647
2648#define UPPER_DOUBLE 1E9
2649#define LOWER_DOUBLE 1E-5
2650
2651#define INTEGER_DIGITS DBL_DIG
2652#define FRACTION_DIGITS (DBL_DIG + 1)
2653#define EXPONENT_DIGITS (3 + 2)
2654
2655/**
2656 * xmlXPathFormatNumber:
2657 * @number: number to format
2658 * @buffer: output buffer
2659 * @buffersize: size of output buffer
2660 *
2661 * Convert the number into a string representation.
2662 */
2663static void
2664xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2665{
Daniel Veillardcda96922001-08-21 10:56:31 +00002666 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002667 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00002668 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002669 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002670 break;
2671 case -1:
2672 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002673 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002674 break;
2675 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00002676 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002677 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002678 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00002679 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002680 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002681 } else if (number == ((int) number)) {
2682 char work[30];
2683 char *ptr, *cur;
Daniel Veillardb3d14912005-09-04 20:47:39 +00002684 int value = (int) number;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002685
2686 ptr = &buffer[0];
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002687 if (value == 0) {
2688 *ptr++ = '0';
2689 } else {
Daniel Veillardb3d14912005-09-04 20:47:39 +00002690 snprintf(work, 29, "%d", value);
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002691 cur = &work[0];
Daniel Veillardb3d14912005-09-04 20:47:39 +00002692 while ((*cur) && (ptr - buffer < buffersize)) {
2693 *ptr++ = *cur++;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002694 }
2695 }
2696 if (ptr - buffer < buffersize) {
2697 *ptr = 0;
2698 } else if (buffersize > 0) {
2699 ptr--;
2700 *ptr = 0;
2701 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002702 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002703 /* 3 is sign, decimal point, and terminating zero */
2704 char work[DBL_DIG + EXPONENT_DIGITS + 3];
2705 int integer_place, fraction_place;
2706 char *ptr;
2707 char *after_fraction;
2708 double absolute_value;
2709 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002710
Bjorn Reese70a9da52001-04-21 16:57:29 +00002711 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002712
Bjorn Reese70a9da52001-04-21 16:57:29 +00002713 /*
2714 * First choose format - scientific or regular floating point.
2715 * In either case, result is in work, and after_fraction points
2716 * just past the fractional part.
2717 */
2718 if ( ((absolute_value > UPPER_DOUBLE) ||
2719 (absolute_value < LOWER_DOUBLE)) &&
2720 (absolute_value != 0.0) ) {
2721 /* Use scientific notation */
2722 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2723 fraction_place = DBL_DIG - 1;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002724 size = snprintf(work, sizeof(work),"%*.*e",
Bjorn Reese70a9da52001-04-21 16:57:29 +00002725 integer_place, fraction_place, number);
Daniel Veillard11ce4002006-03-10 00:36:23 +00002726 while ((size > 0) && (work[size] != 'e')) size--;
2727 after_fraction = work + size;
2728
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002729 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002730 else {
2731 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00002732 if (absolute_value > 0.0)
2733 integer_place = 1 + (int)log10(absolute_value);
2734 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00002735 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002736 fraction_place = (integer_place > 0)
2737 ? DBL_DIG - integer_place
2738 : DBL_DIG;
2739 size = snprintf(work, sizeof(work), "%0.*f",
2740 fraction_place, number);
2741 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002742 }
2743
Bjorn Reese70a9da52001-04-21 16:57:29 +00002744 /* Remove fractional trailing zeroes */
2745 ptr = after_fraction;
2746 while (*(--ptr) == '0')
2747 ;
2748 if (*ptr != '.')
2749 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002750 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002751
2752 /* Finally copy result back to caller */
2753 size = strlen(work) + 1;
2754 if (size > buffersize) {
2755 work[buffersize - 1] = 0;
2756 size = buffersize;
2757 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002758 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002759 }
2760 break;
2761 }
2762}
2763
Owen Taylor3473f882001-02-23 17:55:21 +00002764
2765/************************************************************************
2766 * *
2767 * Routines to handle NodeSets *
2768 * *
2769 ************************************************************************/
2770
2771/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002772 * xmlXPathOrderDocElems:
2773 * @doc: an input document
2774 *
2775 * Call this routine to speed up XPath computation on static documents.
2776 * This stamps all the element nodes with the document order
2777 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00002778 * field, the value stored is actually - the node number (starting at -1)
2779 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002780 *
William M. Brack08171912003-12-29 02:52:11 +00002781 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002782 * of error.
2783 */
2784long
2785xmlXPathOrderDocElems(xmlDocPtr doc) {
2786 long count = 0;
2787 xmlNodePtr cur;
2788
2789 if (doc == NULL)
2790 return(-1);
2791 cur = doc->children;
2792 while (cur != NULL) {
2793 if (cur->type == XML_ELEMENT_NODE) {
2794 cur->content = (void *) (-(++count));
2795 if (cur->children != NULL) {
2796 cur = cur->children;
2797 continue;
2798 }
2799 }
2800 if (cur->next != NULL) {
2801 cur = cur->next;
2802 continue;
2803 }
2804 do {
2805 cur = cur->parent;
2806 if (cur == NULL)
2807 break;
2808 if (cur == (xmlNodePtr) doc) {
2809 cur = NULL;
2810 break;
2811 }
2812 if (cur->next != NULL) {
2813 cur = cur->next;
2814 break;
2815 }
2816 } while (cur != NULL);
2817 }
2818 return(count);
2819}
2820
2821/**
Owen Taylor3473f882001-02-23 17:55:21 +00002822 * xmlXPathCmpNodes:
2823 * @node1: the first node
2824 * @node2: the second node
2825 *
2826 * Compare two nodes w.r.t document order
2827 *
2828 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00002829 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00002830 */
2831int
2832xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2833 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002834 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002835 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002836 xmlNodePtr cur, root;
2837
2838 if ((node1 == NULL) || (node2 == NULL))
2839 return(-2);
2840 /*
2841 * a couple of optimizations which will avoid computations in most cases
2842 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00002843 if (node1->type == XML_ATTRIBUTE_NODE) {
2844 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002845 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002846 node1 = node1->parent;
2847 }
2848 if (node2->type == XML_ATTRIBUTE_NODE) {
2849 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002850 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002851 node2 = node2->parent;
2852 }
2853 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00002854 if (attr1 == attr2) {
2855 /* not required, but we keep attributes in order */
2856 if (attr1 != 0) {
2857 cur = attrNode2->prev;
2858 while (cur != NULL) {
2859 if (cur == attrNode1)
2860 return (1);
2861 cur = cur->prev;
2862 }
2863 return (-1);
2864 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00002865 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00002866 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00002867 if (attr2 == 1)
2868 return(1);
2869 return(-1);
2870 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002871 if ((node1->type == XML_NAMESPACE_DECL) ||
2872 (node2->type == XML_NAMESPACE_DECL))
2873 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00002874 if (node1 == node2->prev)
2875 return(1);
2876 if (node1 == node2->next)
2877 return(-1);
2878
2879 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002880 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002881 */
2882 if ((node1->type == XML_ELEMENT_NODE) &&
2883 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002884 (0 > (long) node1->content) &&
2885 (0 > (long) node2->content) &&
2886 (node1->doc == node2->doc)) {
2887 long l1, l2;
2888
2889 l1 = -((long) node1->content);
2890 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002891 if (l1 < l2)
2892 return(1);
2893 if (l1 > l2)
2894 return(-1);
2895 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002896
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002897 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002898 * compute depth to root
2899 */
2900 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2901 if (cur == node1)
2902 return(1);
2903 depth2++;
2904 }
2905 root = cur;
2906 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2907 if (cur == node2)
2908 return(-1);
2909 depth1++;
2910 }
2911 /*
2912 * Distinct document (or distinct entities :-( ) case.
2913 */
2914 if (root != cur) {
2915 return(-2);
2916 }
2917 /*
2918 * get the nearest common ancestor.
2919 */
2920 while (depth1 > depth2) {
2921 depth1--;
2922 node1 = node1->parent;
2923 }
2924 while (depth2 > depth1) {
2925 depth2--;
2926 node2 = node2->parent;
2927 }
2928 while (node1->parent != node2->parent) {
2929 node1 = node1->parent;
2930 node2 = node2->parent;
2931 /* should not happen but just in case ... */
2932 if ((node1 == NULL) || (node2 == NULL))
2933 return(-2);
2934 }
2935 /*
2936 * Find who's first.
2937 */
Daniel Veillardf49be472004-02-17 11:48:18 +00002938 if (node1 == node2->prev)
2939 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00002940 if (node1 == node2->next)
2941 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00002942 /*
2943 * Speedup using document order if availble.
2944 */
2945 if ((node1->type == XML_ELEMENT_NODE) &&
2946 (node2->type == XML_ELEMENT_NODE) &&
2947 (0 > (long) node1->content) &&
2948 (0 > (long) node2->content) &&
2949 (node1->doc == node2->doc)) {
2950 long l1, l2;
2951
2952 l1 = -((long) node1->content);
2953 l2 = -((long) node2->content);
2954 if (l1 < l2)
2955 return(1);
2956 if (l1 > l2)
2957 return(-1);
2958 }
2959
Owen Taylor3473f882001-02-23 17:55:21 +00002960 for (cur = node1->next;cur != NULL;cur = cur->next)
2961 if (cur == node2)
2962 return(1);
2963 return(-1); /* assume there is no sibling list corruption */
2964}
2965
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00002966#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002967/**
2968 * xmlXPathCmpNodesExt:
2969 * @node1: the first node
2970 * @node2: the second node
2971 *
2972 * Compare two nodes w.r.t document order.
2973 * This one is optimized for handling of non-element nodes.
2974 *
2975 * Returns -2 in case of error 1 if first point < second point, 0 if
2976 * it's the same node, -1 otherwise
2977 */
2978static int
2979xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
2980 int depth1, depth2;
2981 int misc = 0, precedence1 = 0, precedence2 = 0;
2982 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
2983 xmlNodePtr cur, root;
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00002984 long l1, l2;
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002985
2986 if ((node1 == NULL) || (node2 == NULL))
2987 return(-2);
2988
2989 if (node1 == node2)
2990 return(0);
2991
2992 /*
2993 * a couple of optimizations which will avoid computations in most cases
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00002994 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002995 switch (node1->type) {
2996 case XML_ELEMENT_NODE:
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00002997 if (node2->type == XML_ELEMENT_NODE) {
2998 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
2999 (0 > (long) node2->content) &&
3000 (node1->doc == node2->doc))
3001 {
3002 l1 = -((long) node1->content);
3003 l2 = -((long) node2->content);
3004 if (l1 < l2)
3005 return(1);
3006 if (l1 > l2)
3007 return(-1);
3008 } else
3009 goto turtle_comparison;
3010 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003011 break;
3012 case XML_ATTRIBUTE_NODE:
3013 precedence1 = 1; /* element is owner */
3014 miscNode1 = node1;
3015 node1 = node1->parent;
3016 misc = 1;
3017 break;
3018 case XML_TEXT_NODE:
3019 case XML_CDATA_SECTION_NODE:
3020 case XML_COMMENT_NODE:
3021 case XML_PI_NODE: {
3022 miscNode1 = node1;
3023 /*
3024 * Find nearest element node.
3025 */
3026 if (node1->prev != NULL) {
3027 do {
3028 node1 = node1->prev;
3029 if (node1->type == XML_ELEMENT_NODE) {
3030 precedence1 = 3; /* element in prev-sibl axis */
3031 break;
3032 }
3033 if (node1->prev == NULL) {
3034 precedence1 = 2; /* element is parent */
3035 /*
3036 * URGENT TODO: Are there any cases, where the
3037 * parent of such a node is not an element node?
3038 */
3039 node1 = node1->parent;
3040 break;
3041 }
3042 } while (1);
3043 } else {
3044 precedence1 = 2; /* element is parent */
3045 node1 = node1->parent;
3046 }
3047 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE)) {
3048 /*
3049 * Fallback for whatever case.
3050 */
3051 node1 = miscNode1;
3052 precedence1 = 0;
3053 } else
3054 misc = 1;
3055 }
3056 break;
3057 case XML_NAMESPACE_DECL:
3058 /*
3059 * TODO: why do we return 1 for namespace nodes?
3060 */
3061 return(1);
3062 default:
3063 break;
3064 }
3065 switch (node2->type) {
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003066 case XML_ELEMENT_NODE:
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003067 break;
3068 case XML_ATTRIBUTE_NODE:
3069 precedence2 = 1; /* element is owner */
3070 miscNode2 = node2;
3071 node2 = node2->parent;
3072 misc = 1;
3073 break;
3074 case XML_TEXT_NODE:
3075 case XML_CDATA_SECTION_NODE:
3076 case XML_COMMENT_NODE:
3077 case XML_PI_NODE: {
3078 miscNode2 = node2;
3079 if (node2->prev != NULL) {
3080 do {
3081 node2 = node2->prev;
3082 if (node2->type == XML_ELEMENT_NODE) {
3083 precedence2 = 3; /* element in prev-sibl axis */
3084 break;
3085 }
3086 if (node2->prev == NULL) {
3087 precedence2 = 2; /* element is parent */
3088 node2 = node2->parent;
3089 break;
3090 }
3091 } while (1);
3092 } else {
3093 precedence2 = 2; /* element is parent */
3094 node2 = node2->parent;
3095 }
3096 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3097 (0 <= (long) node1->content))
3098 {
3099 node2 = miscNode2;
3100 precedence2 = 0;
3101 } else
3102 misc = 1;
3103 }
3104 break;
3105 case XML_NAMESPACE_DECL:
3106 return(1);
3107 default:
3108 break;
3109 }
3110 if (misc) {
3111 if (node1 == node2) {
3112 if (precedence1 == precedence2) {
3113 /*
3114 * The ugly case; but normally there aren't many
3115 * adjacent non-element nodes around.
3116 */
3117 cur = miscNode2->prev;
3118 while (cur != NULL) {
3119 if (cur == miscNode1)
3120 return(1);
3121 if (cur->type == XML_ELEMENT_NODE)
3122 return(-1);
3123 cur = cur->prev;
3124 }
3125 return (-1);
3126 } else {
3127 /*
3128 * Evaluate based on higher precedence wrt to the element.
3129 * TODO: This assumes attributes are sorted before content.
3130 * Is this 100% correct?
3131 */
3132 if (precedence1 < precedence2)
3133 return(1);
3134 else
3135 return(-1);
3136 }
3137 }
3138 /*
3139 * Special case: One of the helper-elements is contained by the other.
3140 * <foo>
3141 * <node2>
3142 * <node1>Text-1(precedence1 == 2)</node1>
3143 * </node2>
3144 * Text-6(precedence2 == 3)
3145 * </foo>
3146 */
3147 if ((precedence2 == 3) && (precedence1 > 1)) {
3148 cur = node1->parent;
3149 while (cur) {
3150 if (cur == node2)
3151 return(1);
3152 cur = cur->parent;
3153 }
3154 }
3155 if ((precedence1 == 3) && (precedence2 > 1)) {
3156 cur = node2->parent;
3157 while (cur) {
3158 if (cur == node1)
3159 return(-1);
3160 cur = cur->parent;
3161 }
3162 }
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003163 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003164
3165 /*
3166 * Speedup using document order if availble.
3167 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003168 if ((node1->type == XML_ELEMENT_NODE) &&
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003169 (node2->type == XML_ELEMENT_NODE) &&
3170 (0 > (long) node1->content) &&
3171 (0 > (long) node2->content) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003172 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003173
3174 l1 = -((long) node1->content);
3175 l2 = -((long) node2->content);
3176 if (l1 < l2)
3177 return(1);
3178 if (l1 > l2)
3179 return(-1);
3180 }
3181
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003182turtle_comparison:
3183
3184 if (node1 == node2->prev)
3185 return(1);
3186 if (node1 == node2->next)
3187 return(-1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003188 /*
3189 * compute depth to root
3190 */
3191 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3192 if (cur == node1)
3193 return(1);
3194 depth2++;
3195 }
3196 root = cur;
3197 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3198 if (cur == node2)
3199 return(-1);
3200 depth1++;
3201 }
3202 /*
3203 * Distinct document (or distinct entities :-( ) case.
3204 */
3205 if (root != cur) {
3206 return(-2);
3207 }
3208 /*
3209 * get the nearest common ancestor.
3210 */
3211 while (depth1 > depth2) {
3212 depth1--;
3213 node1 = node1->parent;
3214 }
3215 while (depth2 > depth1) {
3216 depth2--;
3217 node2 = node2->parent;
3218 }
3219 while (node1->parent != node2->parent) {
3220 node1 = node1->parent;
3221 node2 = node2->parent;
3222 /* should not happen but just in case ... */
3223 if ((node1 == NULL) || (node2 == NULL))
3224 return(-2);
3225 }
3226 /*
3227 * Find who's first.
3228 */
3229 if (node1 == node2->prev)
3230 return(1);
3231 if (node1 == node2->next)
3232 return(-1);
3233 /*
3234 * Speedup using document order if availble.
3235 */
3236 if ((node1->type == XML_ELEMENT_NODE) &&
3237 (node2->type == XML_ELEMENT_NODE) &&
3238 (0 > (long) node1->content) &&
3239 (0 > (long) node2->content) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003240 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003241
3242 l1 = -((long) node1->content);
3243 l2 = -((long) node2->content);
3244 if (l1 < l2)
3245 return(1);
3246 if (l1 > l2)
3247 return(-1);
3248 }
3249
3250 for (cur = node1->next;cur != NULL;cur = cur->next)
3251 if (cur == node2)
3252 return(1);
3253 return(-1); /* assume there is no sibling list corruption */
3254}
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003255#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003256
Owen Taylor3473f882001-02-23 17:55:21 +00003257/**
3258 * xmlXPathNodeSetSort:
3259 * @set: the node set
3260 *
3261 * Sort the node set in document order
3262 */
3263void
3264xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003265 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003266 xmlNodePtr tmp;
3267
3268 if (set == NULL)
3269 return;
3270
3271 /* Use Shell's sort to sort the node-set */
3272 len = set->nodeNr;
3273 for (incr = len / 2; incr > 0; incr /= 2) {
3274 for (i = incr; i < len; i++) {
3275 j = i - incr;
3276 while (j >= 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003277#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003278 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3279 set->nodeTab[j + incr]) == -1)
3280#else
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003281 if (xmlXPathCmpNodes(set->nodeTab[j],
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003282 set->nodeTab[j + incr]) == -1)
3283#endif
3284 {
Owen Taylor3473f882001-02-23 17:55:21 +00003285 tmp = set->nodeTab[j];
3286 set->nodeTab[j] = set->nodeTab[j + incr];
3287 set->nodeTab[j + incr] = tmp;
3288 j -= incr;
3289 } else
3290 break;
3291 }
3292 }
3293 }
3294}
3295
3296#define XML_NODESET_DEFAULT 10
3297/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003298 * xmlXPathNodeSetDupNs:
3299 * @node: the parent node of the namespace XPath node
3300 * @ns: the libxml namespace declaration node.
3301 *
3302 * Namespace node in libxml don't match the XPath semantic. In a node set
3303 * the namespace nodes are duplicated and the next pointer is set to the
3304 * parent node in the XPath semantic.
3305 *
3306 * Returns the newly created object.
3307 */
3308static xmlNodePtr
3309xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3310 xmlNsPtr cur;
3311
3312 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3313 return(NULL);
3314 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3315 return((xmlNodePtr) ns);
3316
3317 /*
3318 * Allocate a new Namespace and fill the fields.
3319 */
3320 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3321 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003322 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003323 return(NULL);
3324 }
3325 memset(cur, 0, sizeof(xmlNs));
3326 cur->type = XML_NAMESPACE_DECL;
3327 if (ns->href != NULL)
3328 cur->href = xmlStrdup(ns->href);
3329 if (ns->prefix != NULL)
3330 cur->prefix = xmlStrdup(ns->prefix);
3331 cur->next = (xmlNsPtr) node;
3332 return((xmlNodePtr) cur);
3333}
3334
3335/**
3336 * xmlXPathNodeSetFreeNs:
3337 * @ns: the XPath namespace node found in a nodeset.
3338 *
William M. Brack08171912003-12-29 02:52:11 +00003339 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003340 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00003341 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003342 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00003343void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003344xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3345 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3346 return;
3347
3348 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3349 if (ns->href != NULL)
3350 xmlFree((xmlChar *)ns->href);
3351 if (ns->prefix != NULL)
3352 xmlFree((xmlChar *)ns->prefix);
3353 xmlFree(ns);
3354 }
3355}
3356
3357/**
Owen Taylor3473f882001-02-23 17:55:21 +00003358 * xmlXPathNodeSetCreate:
3359 * @val: an initial xmlNodePtr, or NULL
3360 *
3361 * Create a new xmlNodeSetPtr of type double and of value @val
3362 *
3363 * Returns the newly created object.
3364 */
3365xmlNodeSetPtr
3366xmlXPathNodeSetCreate(xmlNodePtr val) {
3367 xmlNodeSetPtr ret;
3368
3369 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3370 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003371 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003372 return(NULL);
3373 }
3374 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3375 if (val != NULL) {
3376 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3377 sizeof(xmlNodePtr));
3378 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003379 xmlXPathErrMemory(NULL, "creating nodeset\n");
3380 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003381 return(NULL);
3382 }
3383 memset(ret->nodeTab, 0 ,
3384 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3385 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003386 if (val->type == XML_NAMESPACE_DECL) {
3387 xmlNsPtr ns = (xmlNsPtr) val;
3388
3389 ret->nodeTab[ret->nodeNr++] =
3390 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3391 } else
3392 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003393 }
3394 return(ret);
3395}
3396
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003397/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003398 * xmlXPathNodeSetCreateSize:
3399 * @size: the initial size of the set
3400 *
3401 * Create a new xmlNodeSetPtr of type double and of value @val
3402 *
3403 * Returns the newly created object.
3404 */
3405static xmlNodeSetPtr
3406xmlXPathNodeSetCreateSize(int size) {
3407 xmlNodeSetPtr ret;
3408
3409 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3410 if (ret == NULL) {
3411 xmlXPathErrMemory(NULL, "creating nodeset\n");
3412 return(NULL);
3413 }
3414 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3415 if (size < XML_NODESET_DEFAULT)
3416 size = XML_NODESET_DEFAULT;
3417 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3418 if (ret->nodeTab == NULL) {
3419 xmlXPathErrMemory(NULL, "creating nodeset\n");
3420 xmlFree(ret);
3421 return(NULL);
3422 }
3423 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3424 ret->nodeMax = size;
3425 return(ret);
3426}
3427
3428/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003429 * xmlXPathNodeSetContains:
3430 * @cur: the node-set
3431 * @val: the node
3432 *
3433 * checks whether @cur contains @val
3434 *
3435 * Returns true (1) if @cur contains @val, false (0) otherwise
3436 */
3437int
3438xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3439 int i;
3440
Daniel Veillarda82b1822004-11-08 16:24:57 +00003441 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003442 if (val->type == XML_NAMESPACE_DECL) {
3443 for (i = 0; i < cur->nodeNr; i++) {
3444 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3445 xmlNsPtr ns1, ns2;
3446
3447 ns1 = (xmlNsPtr) val;
3448 ns2 = (xmlNsPtr) cur->nodeTab[i];
3449 if (ns1 == ns2)
3450 return(1);
3451 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3452 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3453 return(1);
3454 }
3455 }
3456 } else {
3457 for (i = 0; i < cur->nodeNr; i++) {
3458 if (cur->nodeTab[i] == val)
3459 return(1);
3460 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003461 }
3462 return(0);
3463}
3464
3465/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003466 * xmlXPathNodeSetAddNs:
3467 * @cur: the initial node set
3468 * @node: the hosting node
3469 * @ns: a the namespace node
3470 *
3471 * add a new namespace node to an existing NodeSet
3472 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00003473void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003474xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3475 int i;
3476
Daniel Veillarda82b1822004-11-08 16:24:57 +00003477
3478 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3479 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003480 (node->type != XML_ELEMENT_NODE))
3481 return;
3482
William M. Brack08171912003-12-29 02:52:11 +00003483 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003484 /*
William M. Brack08171912003-12-29 02:52:11 +00003485 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003486 */
3487 for (i = 0;i < cur->nodeNr;i++) {
3488 if ((cur->nodeTab[i] != NULL) &&
3489 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00003490 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003491 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3492 return;
3493 }
3494
3495 /*
3496 * grow the nodeTab if needed
3497 */
3498 if (cur->nodeMax == 0) {
3499 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3500 sizeof(xmlNodePtr));
3501 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003502 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003503 return;
3504 }
3505 memset(cur->nodeTab, 0 ,
3506 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3507 cur->nodeMax = XML_NODESET_DEFAULT;
3508 } else if (cur->nodeNr == cur->nodeMax) {
3509 xmlNodePtr *temp;
3510
3511 cur->nodeMax *= 2;
3512 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3513 sizeof(xmlNodePtr));
3514 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003515 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003516 return;
3517 }
3518 cur->nodeTab = temp;
3519 }
3520 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3521}
3522
3523/**
Owen Taylor3473f882001-02-23 17:55:21 +00003524 * xmlXPathNodeSetAdd:
3525 * @cur: the initial node set
3526 * @val: a new xmlNodePtr
3527 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003528 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00003529 */
3530void
3531xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3532 int i;
3533
Daniel Veillarda82b1822004-11-08 16:24:57 +00003534 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003535
Daniel Veillardef0b4502003-03-24 13:57:34 +00003536#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00003537 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3538 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00003539#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00003540
William M. Brack08171912003-12-29 02:52:11 +00003541 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003542 /*
William M. Brack08171912003-12-29 02:52:11 +00003543 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00003544 */
3545 for (i = 0;i < cur->nodeNr;i++)
3546 if (cur->nodeTab[i] == val) return;
3547
3548 /*
3549 * grow the nodeTab if needed
3550 */
3551 if (cur->nodeMax == 0) {
3552 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3553 sizeof(xmlNodePtr));
3554 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003555 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003556 return;
3557 }
3558 memset(cur->nodeTab, 0 ,
3559 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3560 cur->nodeMax = XML_NODESET_DEFAULT;
3561 } else if (cur->nodeNr == cur->nodeMax) {
3562 xmlNodePtr *temp;
3563
3564 cur->nodeMax *= 2;
3565 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3566 sizeof(xmlNodePtr));
3567 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003568 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003569 return;
3570 }
3571 cur->nodeTab = temp;
3572 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003573 if (val->type == XML_NAMESPACE_DECL) {
3574 xmlNsPtr ns = (xmlNsPtr) val;
3575
3576 cur->nodeTab[cur->nodeNr++] =
3577 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3578 } else
3579 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003580}
3581
3582/**
3583 * xmlXPathNodeSetAddUnique:
3584 * @cur: the initial node set
3585 * @val: a new xmlNodePtr
3586 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003587 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00003588 * when we are sure the node is not already in the set.
3589 */
3590void
3591xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00003592 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003593
Daniel Veillardef0b4502003-03-24 13:57:34 +00003594#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00003595 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3596 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00003597#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00003598
William M. Brack08171912003-12-29 02:52:11 +00003599 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003600 /*
3601 * grow the nodeTab if needed
3602 */
3603 if (cur->nodeMax == 0) {
3604 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3605 sizeof(xmlNodePtr));
3606 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003607 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003608 return;
3609 }
3610 memset(cur->nodeTab, 0 ,
3611 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3612 cur->nodeMax = XML_NODESET_DEFAULT;
3613 } else if (cur->nodeNr == cur->nodeMax) {
3614 xmlNodePtr *temp;
3615
3616 cur->nodeMax *= 2;
3617 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3618 sizeof(xmlNodePtr));
3619 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003620 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003621 return;
3622 }
3623 cur->nodeTab = temp;
3624 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003625 if (val->type == XML_NAMESPACE_DECL) {
3626 xmlNsPtr ns = (xmlNsPtr) val;
3627
3628 cur->nodeTab[cur->nodeNr++] =
3629 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3630 } else
3631 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003632}
3633
3634/**
3635 * xmlXPathNodeSetMerge:
3636 * @val1: the first NodeSet or NULL
3637 * @val2: the second NodeSet
3638 *
3639 * Merges two nodesets, all nodes from @val2 are added to @val1
3640 * if @val1 is NULL, a new set is created and copied from @val2
3641 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003642 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003643 */
3644xmlNodeSetPtr
3645xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003646 int i, j, initNr, skip;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003647 xmlNodePtr n1, n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003648
3649 if (val2 == NULL) return(val1);
3650 if (val1 == NULL) {
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003651 val1 = xmlXPathNodeSetCreate(NULL);
3652#if 0
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003653 /*
3654 * TODO: The optimization won't work in every case, since
3655 * those nasty namespace nodes need to be added with
3656 * xmlXPathNodeSetDupNs() to the set; thus a pure
3657 * memcpy is not possible.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00003658 * If there was a flag on the nodesetval, indicating that
3659 * some temporary nodes are in, that would be helpfull.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003660 */
3661 /*
3662 * Optimization: Create an equally sized node-set
3663 * and memcpy the content.
3664 */
3665 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3666 if (val1 == NULL)
3667 return(NULL);
3668 if (val2->nodeNr != 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003669 if (val2->nodeNr == 1)
3670 *(val1->nodeTab) = *(val2->nodeTab);
3671 else {
3672 memcpy(val1->nodeTab, val2->nodeTab,
3673 val2->nodeNr * sizeof(xmlNodePtr));
3674 }
3675 val1->nodeNr = val2->nodeNr;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003676 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003677 return(val1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003678#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003679 }
3680
William M. Brack08171912003-12-29 02:52:11 +00003681 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003682 initNr = val1->nodeNr;
3683
3684 for (i = 0;i < val2->nodeNr;i++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003685 n2 = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00003686 /*
William M. Brack08171912003-12-29 02:52:11 +00003687 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003688 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003689 skip = 0;
3690 for (j = 0; j < initNr; j++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003691 n1 = val1->nodeTab[j];
3692 if (n1 == n2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003693 skip = 1;
3694 break;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003695 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3696 (n2->type == XML_NAMESPACE_DECL)) {
3697 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3698 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3699 ((xmlNsPtr) n2)->prefix)))
3700 {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003701 skip = 1;
3702 break;
3703 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003704 }
3705 }
3706 if (skip)
3707 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00003708
3709 /*
3710 * grow the nodeTab if needed
3711 */
3712 if (val1->nodeMax == 0) {
3713 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3714 sizeof(xmlNodePtr));
3715 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003716 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003717 return(NULL);
3718 }
3719 memset(val1->nodeTab, 0 ,
3720 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3721 val1->nodeMax = XML_NODESET_DEFAULT;
3722 } else if (val1->nodeNr == val1->nodeMax) {
3723 xmlNodePtr *temp;
3724
3725 val1->nodeMax *= 2;
3726 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3727 sizeof(xmlNodePtr));
3728 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003729 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003730 return(NULL);
3731 }
3732 val1->nodeTab = temp;
3733 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003734 if (n2->type == XML_NAMESPACE_DECL) {
3735 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003736
3737 val1->nodeTab[val1->nodeNr++] =
3738 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3739 } else
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003740 val1->nodeTab[val1->nodeNr++] = n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003741 }
3742
3743 return(val1);
3744}
3745
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003746#if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
Owen Taylor3473f882001-02-23 17:55:21 +00003747/**
Daniel Veillard75be0132002-03-13 10:03:35 +00003748 * xmlXPathNodeSetMergeUnique:
3749 * @val1: the first NodeSet or NULL
3750 * @val2: the second NodeSet
3751 *
3752 * Merges two nodesets, all nodes from @val2 are added to @val1
3753 * if @val1 is NULL, a new set is created and copied from @val2
3754 *
3755 * Returns @val1 once extended or NULL in case of error.
3756 */
3757static xmlNodeSetPtr
3758xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00003759 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00003760
3761 if (val2 == NULL) return(val1);
3762 if (val1 == NULL) {
3763 val1 = xmlXPathNodeSetCreate(NULL);
3764 }
3765
William M. Brack08171912003-12-29 02:52:11 +00003766 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00003767
3768 for (i = 0;i < val2->nodeNr;i++) {
3769 /*
3770 * grow the nodeTab if needed
3771 */
3772 if (val1->nodeMax == 0) {
3773 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3774 sizeof(xmlNodePtr));
3775 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003776 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00003777 return(NULL);
3778 }
3779 memset(val1->nodeTab, 0 ,
3780 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3781 val1->nodeMax = XML_NODESET_DEFAULT;
3782 } else if (val1->nodeNr == val1->nodeMax) {
3783 xmlNodePtr *temp;
3784
3785 val1->nodeMax *= 2;
3786 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3787 sizeof(xmlNodePtr));
3788 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003789 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00003790 return(NULL);
3791 }
3792 val1->nodeTab = temp;
3793 }
3794 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3795 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
3796
3797 val1->nodeTab[val1->nodeNr++] =
3798 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3799 } else
3800 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
3801 }
3802
3803 return(val1);
3804}
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003805#endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3806
3807/**
3808 * xmlXPathNodeSetMergeAndClear:
3809 * @set1: the first NodeSet or NULL
3810 * @set2: the second NodeSet
3811 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3812 *
3813 * Merges two nodesets, all nodes from @set2 are added to @set1
3814 * if @set1 is NULL, a new set is created and copied from @set2.
3815 * Checks for duplicate nodes. Clears set2.
3816 *
3817 * Returns @set1 once extended or NULL in case of error.
3818 */
3819static xmlNodeSetPtr
3820xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3821 int hasNullEntries)
3822{
3823 if ((set1 == NULL) && (hasNullEntries == 0)) {
3824 /*
3825 * Note that doing a memcpy of the list, namespace nodes are
3826 * just assigned to set1, since set2 is cleared anyway.
3827 */
3828 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3829 if (set1 == NULL)
3830 return(NULL);
3831 if (set2->nodeNr != 0) {
3832 memcpy(set1->nodeTab, set2->nodeTab,
3833 set2->nodeNr * sizeof(xmlNodePtr));
3834 set1->nodeNr = set2->nodeNr;
3835 }
3836 } else {
3837 int i, j, initNbSet1;
3838 xmlNodePtr n1, n2;
3839
3840 if (set1 == NULL)
3841 set1 = xmlXPathNodeSetCreate(NULL);
3842
3843 initNbSet1 = set1->nodeNr;
3844 for (i = 0;i < set2->nodeNr;i++) {
3845 n2 = set2->nodeTab[i];
3846 /*
3847 * Skip NULLed entries.
3848 */
3849 if (n2 == NULL)
3850 continue;
3851 /*
3852 * Skip duplicates.
3853 */
3854 for (j = 0; j < initNbSet1; j++) {
3855 n1 = set1->nodeTab[j];
3856 if (n1 == n2) {
3857 goto skip_node;
3858 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3859 (n2->type == XML_NAMESPACE_DECL))
3860 {
3861 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3862 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3863 ((xmlNsPtr) n2)->prefix)))
3864 {
3865 /*
3866 * Free the namespace node.
3867 */
3868 set2->nodeTab[i] = NULL;
3869 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3870 goto skip_node;
3871 }
3872 }
3873 }
3874 /*
3875 * grow the nodeTab if needed
3876 */
3877 if (set1->nodeMax == 0) {
3878 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3879 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3880 if (set1->nodeTab == NULL) {
3881 xmlXPathErrMemory(NULL, "merging nodeset\n");
3882 return(NULL);
3883 }
3884 memset(set1->nodeTab, 0,
3885 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3886 set1->nodeMax = XML_NODESET_DEFAULT;
3887 } else if (set1->nodeNr >= set1->nodeMax) {
3888 xmlNodePtr *temp;
3889
3890 set1->nodeMax *= 2;
3891 temp = (xmlNodePtr *) xmlRealloc(
3892 set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3893 if (temp == NULL) {
3894 xmlXPathErrMemory(NULL, "merging nodeset\n");
3895 return(NULL);
3896 }
3897 set1->nodeTab = temp;
3898 }
3899 if (n2->type == XML_NAMESPACE_DECL) {
3900 xmlNsPtr ns = (xmlNsPtr) n2;
3901
3902 set1->nodeTab[set1->nodeNr++] =
3903 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3904 } else
3905 set1->nodeTab[set1->nodeNr++] = n2;
3906skip_node:
3907 {}
3908 }
3909 }
3910 set2->nodeNr = 0;
3911 return(set1);
3912}
3913
3914/**
3915 * xmlXPathNodeSetMergeAndClearNoDupls:
3916 * @set1: the first NodeSet or NULL
3917 * @set2: the second NodeSet
3918 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3919 *
3920 * Merges two nodesets, all nodes from @set2 are added to @set1
3921 * if @set1 is NULL, a new set is created and copied from @set2.
3922 * Doesn't chack for duplicate nodes. Clears set2.
3923 *
3924 * Returns @set1 once extended or NULL in case of error.
3925 */
3926static xmlNodeSetPtr
3927xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3928 int hasNullEntries)
3929{
3930 if (set2 == NULL)
3931 return(set1);
3932 if ((set1 == NULL) && (hasNullEntries == 0)) {
3933 /*
3934 * Note that doing a memcpy of the list, namespace nodes are
3935 * just assigned to set1, since set2 is cleared anyway.
3936 */
3937 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3938 if (set1 == NULL)
3939 return(NULL);
3940 if (set2->nodeNr != 0) {
3941 memcpy(set1->nodeTab, set2->nodeTab,
3942 set2->nodeNr * sizeof(xmlNodePtr));
3943 set1->nodeNr = set2->nodeNr;
3944 }
3945 } else {
3946 int i;
3947 xmlNodePtr n2;
3948
3949 if (set1 == NULL)
3950 set1 = xmlXPathNodeSetCreate(NULL);
3951
3952 for (i = 0;i < set2->nodeNr;i++) {
3953 n2 = set2->nodeTab[i];
3954 /*
3955 * Skip NULLed entries.
3956 */
3957 if (n2 == NULL)
3958 continue;
3959 if (set1->nodeMax == 0) {
3960 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3961 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3962 if (set1->nodeTab == NULL) {
3963 xmlXPathErrMemory(NULL, "merging nodeset\n");
3964 return(NULL);
3965 }
3966 memset(set1->nodeTab, 0,
3967 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3968 set1->nodeMax = XML_NODESET_DEFAULT;
3969 } else if (set1->nodeNr >= set1->nodeMax) {
3970 xmlNodePtr *temp;
3971
3972 set1->nodeMax *= 2;
3973 temp = (xmlNodePtr *) xmlRealloc(
3974 set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3975 if (temp == NULL) {
3976 xmlXPathErrMemory(NULL, "merging nodeset\n");
3977 return(NULL);
3978 }
3979 set1->nodeTab = temp;
3980 }
3981 set1->nodeTab[set1->nodeNr++] = n2;
3982 }
3983 }
3984 set2->nodeNr = 0;
3985 return(set1);
3986}
Daniel Veillard75be0132002-03-13 10:03:35 +00003987
3988/**
Owen Taylor3473f882001-02-23 17:55:21 +00003989 * xmlXPathNodeSetDel:
3990 * @cur: the initial node set
3991 * @val: an xmlNodePtr
3992 *
3993 * Removes an xmlNodePtr from an existing NodeSet
3994 */
3995void
3996xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
3997 int i;
3998
3999 if (cur == NULL) return;
4000 if (val == NULL) return;
4001
4002 /*
William M. Brack08171912003-12-29 02:52:11 +00004003 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00004004 */
4005 for (i = 0;i < cur->nodeNr;i++)
4006 if (cur->nodeTab[i] == val) break;
4007
William M. Brack08171912003-12-29 02:52:11 +00004008 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00004009#ifdef DEBUG
4010 xmlGenericError(xmlGenericErrorContext,
4011 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4012 val->name);
4013#endif
4014 return;
4015 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004016 if ((cur->nodeTab[i] != NULL) &&
4017 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4018 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004019 cur->nodeNr--;
4020 for (;i < cur->nodeNr;i++)
4021 cur->nodeTab[i] = cur->nodeTab[i + 1];
4022 cur->nodeTab[cur->nodeNr] = NULL;
4023}
4024
4025/**
4026 * xmlXPathNodeSetRemove:
4027 * @cur: the initial node set
4028 * @val: the index to remove
4029 *
4030 * Removes an entry from an existing NodeSet list.
4031 */
4032void
4033xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4034 if (cur == NULL) return;
4035 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004036 if ((cur->nodeTab[val] != NULL) &&
4037 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4038 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00004039 cur->nodeNr--;
4040 for (;val < cur->nodeNr;val++)
4041 cur->nodeTab[val] = cur->nodeTab[val + 1];
4042 cur->nodeTab[cur->nodeNr] = NULL;
4043}
4044
4045/**
4046 * xmlXPathFreeNodeSet:
4047 * @obj: the xmlNodeSetPtr to free
4048 *
4049 * Free the NodeSet compound (not the actual nodes !).
4050 */
4051void
4052xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4053 if (obj == NULL) return;
4054 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004055 int i;
4056
William M. Brack08171912003-12-29 02:52:11 +00004057 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004058 for (i = 0;i < obj->nodeNr;i++)
4059 if ((obj->nodeTab[i] != NULL) &&
4060 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4061 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004062 xmlFree(obj->nodeTab);
4063 }
Owen Taylor3473f882001-02-23 17:55:21 +00004064 xmlFree(obj);
4065}
4066
4067/**
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004068 * xmlXPathNodeSetClear:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004069 * @set: the node set to clear
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004070 *
4071 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4072 * are feed), but does *not* free the list itself. Sets the length of the
4073 * list to 0.
4074 */
4075static void
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004076xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4077{
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004078 if ((set == NULL) || (set->nodeNr <= 0))
4079 return;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004080 else if (hasNsNodes) {
4081 int i;
4082 xmlNodePtr node;
4083
4084 for (i = 0; i < set->nodeNr; i++) {
4085 node = set->nodeTab[i];
4086 if ((node != NULL) &&
4087 (node->type == XML_NAMESPACE_DECL))
4088 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4089 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004090 }
4091 set->nodeNr = 0;
4092}
4093
4094/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004095 * xmlXPathNodeSetClearFromPos:
4096 * @set: the node set to be cleared
4097 * @pos: the start position to clear from
4098 *
4099 * Clears the list from temporary XPath objects (e.g. namespace nodes
4100 * are feed) starting with the entry at @pos, but does *not* free the list
4101 * itself. Sets the length of the list to @pos.
4102 */
4103static void
4104xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4105{
4106 if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4107 return;
4108 else if ((hasNsNodes)) {
4109 int i;
4110 xmlNodePtr node;
4111
4112 for (i = pos; i < set->nodeNr; i++) {
4113 node = set->nodeTab[i];
4114 if ((node != NULL) &&
4115 (node->type == XML_NAMESPACE_DECL))
4116 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4117 }
4118 }
4119 set->nodeNr = pos;
4120}
4121
4122/**
Owen Taylor3473f882001-02-23 17:55:21 +00004123 * xmlXPathFreeValueTree:
4124 * @obj: the xmlNodeSetPtr to free
4125 *
4126 * Free the NodeSet compound and the actual tree, this is different
4127 * from xmlXPathFreeNodeSet()
4128 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004129static void
Owen Taylor3473f882001-02-23 17:55:21 +00004130xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4131 int i;
4132
4133 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00004134
4135 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004136 for (i = 0;i < obj->nodeNr;i++) {
4137 if (obj->nodeTab[i] != NULL) {
4138 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4139 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4140 } else {
4141 xmlFreeNodeList(obj->nodeTab[i]);
4142 }
4143 }
4144 }
Owen Taylor3473f882001-02-23 17:55:21 +00004145 xmlFree(obj->nodeTab);
4146 }
Owen Taylor3473f882001-02-23 17:55:21 +00004147 xmlFree(obj);
4148}
4149
4150#if defined(DEBUG) || defined(DEBUG_STEP)
4151/**
4152 * xmlGenericErrorContextNodeSet:
4153 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00004154 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00004155 *
4156 * Quick display of a NodeSet
4157 */
4158void
4159xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4160 int i;
4161
4162 if (output == NULL) output = xmlGenericErrorContext;
4163 if (obj == NULL) {
4164 fprintf(output, "NodeSet == NULL !\n");
4165 return;
4166 }
4167 if (obj->nodeNr == 0) {
4168 fprintf(output, "NodeSet is empty\n");
4169 return;
4170 }
4171 if (obj->nodeTab == NULL) {
4172 fprintf(output, " nodeTab == NULL !\n");
4173 return;
4174 }
4175 for (i = 0; i < obj->nodeNr; i++) {
4176 if (obj->nodeTab[i] == NULL) {
4177 fprintf(output, " NULL !\n");
4178 return;
4179 }
4180 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4181 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4182 fprintf(output, " /");
4183 else if (obj->nodeTab[i]->name == NULL)
4184 fprintf(output, " noname!");
4185 else fprintf(output, " %s", obj->nodeTab[i]->name);
4186 }
4187 fprintf(output, "\n");
4188}
4189#endif
4190
4191/**
4192 * xmlXPathNewNodeSet:
4193 * @val: the NodePtr value
4194 *
4195 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4196 * it with the single Node @val
4197 *
4198 * Returns the newly created object.
4199 */
4200xmlXPathObjectPtr
4201xmlXPathNewNodeSet(xmlNodePtr val) {
4202 xmlXPathObjectPtr ret;
4203
4204 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4205 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004206 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004207 return(NULL);
4208 }
4209 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4210 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00004211 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004212 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00004213 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004214#ifdef XP_DEBUG_OBJ_USAGE
4215 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4216#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004217 return(ret);
4218}
4219
4220/**
4221 * xmlXPathNewValueTree:
4222 * @val: the NodePtr value
4223 *
4224 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4225 * it with the tree root @val
4226 *
4227 * Returns the newly created object.
4228 */
4229xmlXPathObjectPtr
4230xmlXPathNewValueTree(xmlNodePtr val) {
4231 xmlXPathObjectPtr ret;
4232
4233 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4234 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004235 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004236 return(NULL);
4237 }
4238 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4239 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00004240 ret->boolval = 1;
4241 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00004242 ret->nodesetval = xmlXPathNodeSetCreate(val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004243#ifdef XP_DEBUG_OBJ_USAGE
4244 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4245#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004246 return(ret);
4247}
4248
4249/**
4250 * xmlXPathNewNodeSetList:
4251 * @val: an existing NodeSet
4252 *
4253 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4254 * it with the Nodeset @val
4255 *
4256 * Returns the newly created object.
4257 */
4258xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004259xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4260{
Owen Taylor3473f882001-02-23 17:55:21 +00004261 xmlXPathObjectPtr ret;
4262 int i;
4263
4264 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004265 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00004266 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004267 ret = xmlXPathNewNodeSet(NULL);
4268 else {
4269 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4270 for (i = 1; i < val->nodeNr; ++i)
4271 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
4272 }
Owen Taylor3473f882001-02-23 17:55:21 +00004273
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004274 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004275}
4276
4277/**
4278 * xmlXPathWrapNodeSet:
4279 * @val: the NodePtr value
4280 *
4281 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4282 *
4283 * Returns the newly created object.
4284 */
4285xmlXPathObjectPtr
4286xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4287 xmlXPathObjectPtr ret;
4288
4289 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4290 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004291 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004292 return(NULL);
4293 }
4294 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4295 ret->type = XPATH_NODESET;
4296 ret->nodesetval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004297#ifdef XP_DEBUG_OBJ_USAGE
4298 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4299#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004300 return(ret);
4301}
4302
4303/**
4304 * xmlXPathFreeNodeSetList:
4305 * @obj: an existing NodeSetList object
4306 *
4307 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4308 * the list contrary to xmlXPathFreeObject().
4309 */
4310void
4311xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4312 if (obj == NULL) return;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004313#ifdef XP_DEBUG_OBJ_USAGE
4314 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4315#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004316 xmlFree(obj);
4317}
4318
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004319/**
4320 * xmlXPathDifference:
4321 * @nodes1: a node-set
4322 * @nodes2: a node-set
4323 *
4324 * Implements the EXSLT - Sets difference() function:
4325 * node-set set:difference (node-set, node-set)
4326 *
4327 * Returns the difference between the two node sets, or nodes1 if
4328 * nodes2 is empty
4329 */
4330xmlNodeSetPtr
4331xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4332 xmlNodeSetPtr ret;
4333 int i, l1;
4334 xmlNodePtr cur;
4335
4336 if (xmlXPathNodeSetIsEmpty(nodes2))
4337 return(nodes1);
4338
4339 ret = xmlXPathNodeSetCreate(NULL);
4340 if (xmlXPathNodeSetIsEmpty(nodes1))
4341 return(ret);
4342
4343 l1 = xmlXPathNodeSetGetLength(nodes1);
4344
4345 for (i = 0; i < l1; i++) {
4346 cur = xmlXPathNodeSetItem(nodes1, i);
4347 if (!xmlXPathNodeSetContains(nodes2, cur))
4348 xmlXPathNodeSetAddUnique(ret, cur);
4349 }
4350 return(ret);
4351}
4352
4353/**
4354 * xmlXPathIntersection:
4355 * @nodes1: a node-set
4356 * @nodes2: a node-set
4357 *
4358 * Implements the EXSLT - Sets intersection() function:
4359 * node-set set:intersection (node-set, node-set)
4360 *
4361 * Returns a node set comprising the nodes that are within both the
4362 * node sets passed as arguments
4363 */
4364xmlNodeSetPtr
4365xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4366 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4367 int i, l1;
4368 xmlNodePtr cur;
4369
4370 if (xmlXPathNodeSetIsEmpty(nodes1))
4371 return(ret);
4372 if (xmlXPathNodeSetIsEmpty(nodes2))
4373 return(ret);
4374
4375 l1 = xmlXPathNodeSetGetLength(nodes1);
4376
4377 for (i = 0; i < l1; i++) {
4378 cur = xmlXPathNodeSetItem(nodes1, i);
4379 if (xmlXPathNodeSetContains(nodes2, cur))
4380 xmlXPathNodeSetAddUnique(ret, cur);
4381 }
4382 return(ret);
4383}
4384
4385/**
4386 * xmlXPathDistinctSorted:
4387 * @nodes: a node-set, sorted by document order
4388 *
4389 * Implements the EXSLT - Sets distinct() function:
4390 * node-set set:distinct (node-set)
4391 *
4392 * Returns a subset of the nodes contained in @nodes, or @nodes if
4393 * it is empty
4394 */
4395xmlNodeSetPtr
4396xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4397 xmlNodeSetPtr ret;
4398 xmlHashTablePtr hash;
4399 int i, l;
4400 xmlChar * strval;
4401 xmlNodePtr cur;
4402
4403 if (xmlXPathNodeSetIsEmpty(nodes))
4404 return(nodes);
4405
4406 ret = xmlXPathNodeSetCreate(NULL);
4407 l = xmlXPathNodeSetGetLength(nodes);
4408 hash = xmlHashCreate (l);
4409 for (i = 0; i < l; i++) {
4410 cur = xmlXPathNodeSetItem(nodes, i);
4411 strval = xmlXPathCastNodeToString(cur);
4412 if (xmlHashLookup(hash, strval) == NULL) {
4413 xmlHashAddEntry(hash, strval, strval);
4414 xmlXPathNodeSetAddUnique(ret, cur);
4415 } else {
4416 xmlFree(strval);
4417 }
4418 }
4419 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4420 return(ret);
4421}
4422
4423/**
4424 * xmlXPathDistinct:
4425 * @nodes: a node-set
4426 *
4427 * Implements the EXSLT - Sets distinct() function:
4428 * node-set set:distinct (node-set)
4429 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4430 * is called with the sorted node-set
4431 *
4432 * Returns a subset of the nodes contained in @nodes, or @nodes if
4433 * it is empty
4434 */
4435xmlNodeSetPtr
4436xmlXPathDistinct (xmlNodeSetPtr nodes) {
4437 if (xmlXPathNodeSetIsEmpty(nodes))
4438 return(nodes);
4439
4440 xmlXPathNodeSetSort(nodes);
4441 return(xmlXPathDistinctSorted(nodes));
4442}
4443
4444/**
4445 * xmlXPathHasSameNodes:
4446 * @nodes1: a node-set
4447 * @nodes2: a node-set
4448 *
4449 * Implements the EXSLT - Sets has-same-nodes function:
4450 * boolean set:has-same-node(node-set, node-set)
4451 *
4452 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4453 * otherwise
4454 */
4455int
4456xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4457 int i, l;
4458 xmlNodePtr cur;
4459
4460 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4461 xmlXPathNodeSetIsEmpty(nodes2))
4462 return(0);
4463
4464 l = xmlXPathNodeSetGetLength(nodes1);
4465 for (i = 0; i < l; i++) {
4466 cur = xmlXPathNodeSetItem(nodes1, i);
4467 if (xmlXPathNodeSetContains(nodes2, cur))
4468 return(1);
4469 }
4470 return(0);
4471}
4472
4473/**
4474 * xmlXPathNodeLeadingSorted:
4475 * @nodes: a node-set, sorted by document order
4476 * @node: a node
4477 *
4478 * Implements the EXSLT - Sets leading() function:
4479 * node-set set:leading (node-set, node-set)
4480 *
4481 * Returns the nodes in @nodes that precede @node in document order,
4482 * @nodes if @node is NULL or an empty node-set if @nodes
4483 * doesn't contain @node
4484 */
4485xmlNodeSetPtr
4486xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4487 int i, l;
4488 xmlNodePtr cur;
4489 xmlNodeSetPtr ret;
4490
4491 if (node == NULL)
4492 return(nodes);
4493
4494 ret = xmlXPathNodeSetCreate(NULL);
4495 if (xmlXPathNodeSetIsEmpty(nodes) ||
4496 (!xmlXPathNodeSetContains(nodes, node)))
4497 return(ret);
4498
4499 l = xmlXPathNodeSetGetLength(nodes);
4500 for (i = 0; i < l; i++) {
4501 cur = xmlXPathNodeSetItem(nodes, i);
4502 if (cur == node)
4503 break;
4504 xmlXPathNodeSetAddUnique(ret, cur);
4505 }
4506 return(ret);
4507}
4508
4509/**
4510 * xmlXPathNodeLeading:
4511 * @nodes: a node-set
4512 * @node: a node
4513 *
4514 * Implements the EXSLT - Sets leading() function:
4515 * node-set set:leading (node-set, node-set)
4516 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4517 * is called.
4518 *
4519 * Returns the nodes in @nodes that precede @node in document order,
4520 * @nodes if @node is NULL or an empty node-set if @nodes
4521 * doesn't contain @node
4522 */
4523xmlNodeSetPtr
4524xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4525 xmlXPathNodeSetSort(nodes);
4526 return(xmlXPathNodeLeadingSorted(nodes, node));
4527}
4528
4529/**
4530 * xmlXPathLeadingSorted:
4531 * @nodes1: a node-set, sorted by document order
4532 * @nodes2: a node-set, sorted by document order
4533 *
4534 * Implements the EXSLT - Sets leading() function:
4535 * node-set set:leading (node-set, node-set)
4536 *
4537 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4538 * in document order, @nodes1 if @nodes2 is NULL or empty or
4539 * an empty node-set if @nodes1 doesn't contain @nodes2
4540 */
4541xmlNodeSetPtr
4542xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4543 if (xmlXPathNodeSetIsEmpty(nodes2))
4544 return(nodes1);
4545 return(xmlXPathNodeLeadingSorted(nodes1,
4546 xmlXPathNodeSetItem(nodes2, 1)));
4547}
4548
4549/**
4550 * xmlXPathLeading:
4551 * @nodes1: a node-set
4552 * @nodes2: a node-set
4553 *
4554 * Implements the EXSLT - Sets leading() function:
4555 * node-set set:leading (node-set, node-set)
4556 * @nodes1 and @nodes2 are sorted by document order, then
4557 * #exslSetsLeadingSorted is called.
4558 *
4559 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4560 * in document order, @nodes1 if @nodes2 is NULL or empty or
4561 * an empty node-set if @nodes1 doesn't contain @nodes2
4562 */
4563xmlNodeSetPtr
4564xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4565 if (xmlXPathNodeSetIsEmpty(nodes2))
4566 return(nodes1);
4567 if (xmlXPathNodeSetIsEmpty(nodes1))
4568 return(xmlXPathNodeSetCreate(NULL));
4569 xmlXPathNodeSetSort(nodes1);
4570 xmlXPathNodeSetSort(nodes2);
4571 return(xmlXPathNodeLeadingSorted(nodes1,
4572 xmlXPathNodeSetItem(nodes2, 1)));
4573}
4574
4575/**
4576 * xmlXPathNodeTrailingSorted:
4577 * @nodes: a node-set, sorted by document order
4578 * @node: a node
4579 *
4580 * Implements the EXSLT - Sets trailing() function:
4581 * node-set set:trailing (node-set, node-set)
4582 *
4583 * Returns the nodes in @nodes that follow @node in document order,
4584 * @nodes if @node is NULL or an empty node-set if @nodes
4585 * doesn't contain @node
4586 */
4587xmlNodeSetPtr
4588xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4589 int i, l;
4590 xmlNodePtr cur;
4591 xmlNodeSetPtr ret;
4592
4593 if (node == NULL)
4594 return(nodes);
4595
4596 ret = xmlXPathNodeSetCreate(NULL);
4597 if (xmlXPathNodeSetIsEmpty(nodes) ||
4598 (!xmlXPathNodeSetContains(nodes, node)))
4599 return(ret);
4600
4601 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00004602 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004603 cur = xmlXPathNodeSetItem(nodes, i);
4604 if (cur == node)
4605 break;
4606 xmlXPathNodeSetAddUnique(ret, cur);
4607 }
4608 return(ret);
4609}
4610
4611/**
4612 * xmlXPathNodeTrailing:
4613 * @nodes: a node-set
4614 * @node: a node
4615 *
4616 * Implements the EXSLT - Sets trailing() function:
4617 * node-set set:trailing (node-set, node-set)
4618 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4619 * is called.
4620 *
4621 * Returns the nodes in @nodes that follow @node in document order,
4622 * @nodes if @node is NULL or an empty node-set if @nodes
4623 * doesn't contain @node
4624 */
4625xmlNodeSetPtr
4626xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4627 xmlXPathNodeSetSort(nodes);
4628 return(xmlXPathNodeTrailingSorted(nodes, node));
4629}
4630
4631/**
4632 * xmlXPathTrailingSorted:
4633 * @nodes1: a node-set, sorted by document order
4634 * @nodes2: a node-set, sorted by document order
4635 *
4636 * Implements the EXSLT - Sets trailing() function:
4637 * node-set set:trailing (node-set, node-set)
4638 *
4639 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4640 * in document order, @nodes1 if @nodes2 is NULL or empty or
4641 * an empty node-set if @nodes1 doesn't contain @nodes2
4642 */
4643xmlNodeSetPtr
4644xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4645 if (xmlXPathNodeSetIsEmpty(nodes2))
4646 return(nodes1);
4647 return(xmlXPathNodeTrailingSorted(nodes1,
4648 xmlXPathNodeSetItem(nodes2, 0)));
4649}
4650
4651/**
4652 * xmlXPathTrailing:
4653 * @nodes1: a node-set
4654 * @nodes2: a node-set
4655 *
4656 * Implements the EXSLT - Sets trailing() function:
4657 * node-set set:trailing (node-set, node-set)
4658 * @nodes1 and @nodes2 are sorted by document order, then
4659 * #xmlXPathTrailingSorted is called.
4660 *
4661 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4662 * in document order, @nodes1 if @nodes2 is NULL or empty or
4663 * an empty node-set if @nodes1 doesn't contain @nodes2
4664 */
4665xmlNodeSetPtr
4666xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4667 if (xmlXPathNodeSetIsEmpty(nodes2))
4668 return(nodes1);
4669 if (xmlXPathNodeSetIsEmpty(nodes1))
4670 return(xmlXPathNodeSetCreate(NULL));
4671 xmlXPathNodeSetSort(nodes1);
4672 xmlXPathNodeSetSort(nodes2);
4673 return(xmlXPathNodeTrailingSorted(nodes1,
4674 xmlXPathNodeSetItem(nodes2, 0)));
4675}
4676
Owen Taylor3473f882001-02-23 17:55:21 +00004677/************************************************************************
4678 * *
4679 * Routines to handle extra functions *
4680 * *
4681 ************************************************************************/
4682
4683/**
4684 * xmlXPathRegisterFunc:
4685 * @ctxt: the XPath context
4686 * @name: the function name
4687 * @f: the function implementation or NULL
4688 *
4689 * Register a new function. If @f is NULL it unregisters the function
4690 *
4691 * Returns 0 in case of success, -1 in case of error
4692 */
4693int
4694xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4695 xmlXPathFunction f) {
4696 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4697}
4698
4699/**
4700 * xmlXPathRegisterFuncNS:
4701 * @ctxt: the XPath context
4702 * @name: the function name
4703 * @ns_uri: the function namespace URI
4704 * @f: the function implementation or NULL
4705 *
4706 * Register a new function. If @f is NULL it unregisters the function
4707 *
4708 * Returns 0 in case of success, -1 in case of error
4709 */
4710int
4711xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4712 const xmlChar *ns_uri, xmlXPathFunction f) {
4713 if (ctxt == NULL)
4714 return(-1);
4715 if (name == NULL)
4716 return(-1);
4717
4718 if (ctxt->funcHash == NULL)
4719 ctxt->funcHash = xmlHashCreate(0);
4720 if (ctxt->funcHash == NULL)
4721 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004722 if (f == NULL)
4723 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
William M. Brackad0e67c2004-12-01 14:35:10 +00004724 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
Owen Taylor3473f882001-02-23 17:55:21 +00004725}
4726
4727/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00004728 * xmlXPathRegisterFuncLookup:
4729 * @ctxt: the XPath context
4730 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004731 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00004732 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004733 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00004734 */
4735void
4736xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4737 xmlXPathFuncLookupFunc f,
4738 void *funcCtxt) {
4739 if (ctxt == NULL)
4740 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004741 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004742 ctxt->funcLookupData = funcCtxt;
4743}
4744
4745/**
Owen Taylor3473f882001-02-23 17:55:21 +00004746 * xmlXPathFunctionLookup:
4747 * @ctxt: the XPath context
4748 * @name: the function name
4749 *
4750 * Search in the Function array of the context for the given
4751 * function.
4752 *
4753 * Returns the xmlXPathFunction or NULL if not found
4754 */
4755xmlXPathFunction
4756xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00004757 if (ctxt == NULL)
4758 return (NULL);
4759
4760 if (ctxt->funcLookupFunc != NULL) {
4761 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004762 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004763
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004764 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004765 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004766 if (ret != NULL)
4767 return(ret);
4768 }
Owen Taylor3473f882001-02-23 17:55:21 +00004769 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4770}
4771
4772/**
4773 * xmlXPathFunctionLookupNS:
4774 * @ctxt: the XPath context
4775 * @name: the function name
4776 * @ns_uri: the function namespace URI
4777 *
4778 * Search in the Function array of the context for the given
4779 * function.
4780 *
4781 * Returns the xmlXPathFunction or NULL if not found
4782 */
4783xmlXPathFunction
4784xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4785 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00004786 xmlXPathFunction ret;
4787
Owen Taylor3473f882001-02-23 17:55:21 +00004788 if (ctxt == NULL)
4789 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004790 if (name == NULL)
4791 return(NULL);
4792
Thomas Broyerba4ad322001-07-26 16:55:21 +00004793 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004794 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004795
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004796 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004797 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004798 if (ret != NULL)
4799 return(ret);
4800 }
4801
4802 if (ctxt->funcHash == NULL)
4803 return(NULL);
4804
William M. Brackad0e67c2004-12-01 14:35:10 +00004805 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4806 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004807}
4808
4809/**
4810 * xmlXPathRegisteredFuncsCleanup:
4811 * @ctxt: the XPath context
4812 *
4813 * Cleanup the XPath context data associated to registered functions
4814 */
4815void
4816xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4817 if (ctxt == NULL)
4818 return;
4819
4820 xmlHashFree(ctxt->funcHash, NULL);
4821 ctxt->funcHash = NULL;
4822}
4823
4824/************************************************************************
4825 * *
William M. Brack08171912003-12-29 02:52:11 +00004826 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00004827 * *
4828 ************************************************************************/
4829
4830/**
4831 * xmlXPathRegisterVariable:
4832 * @ctxt: the XPath context
4833 * @name: the variable name
4834 * @value: the variable value or NULL
4835 *
4836 * Register a new variable value. If @value is NULL it unregisters
4837 * the variable
4838 *
4839 * Returns 0 in case of success, -1 in case of error
4840 */
4841int
4842xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4843 xmlXPathObjectPtr value) {
4844 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4845}
4846
4847/**
4848 * xmlXPathRegisterVariableNS:
4849 * @ctxt: the XPath context
4850 * @name: the variable name
4851 * @ns_uri: the variable namespace URI
4852 * @value: the variable value or NULL
4853 *
4854 * Register a new variable value. If @value is NULL it unregisters
4855 * the variable
4856 *
4857 * Returns 0 in case of success, -1 in case of error
4858 */
4859int
4860xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4861 const xmlChar *ns_uri,
4862 xmlXPathObjectPtr value) {
4863 if (ctxt == NULL)
4864 return(-1);
4865 if (name == NULL)
4866 return(-1);
4867
4868 if (ctxt->varHash == NULL)
4869 ctxt->varHash = xmlHashCreate(0);
4870 if (ctxt->varHash == NULL)
4871 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004872 if (value == NULL)
4873 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4874 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00004875 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4876 (void *) value,
4877 (xmlHashDeallocator)xmlXPathFreeObject));
4878}
4879
4880/**
4881 * xmlXPathRegisterVariableLookup:
4882 * @ctxt: the XPath context
4883 * @f: the lookup function
4884 * @data: the lookup data
4885 *
4886 * register an external mechanism to do variable lookup
4887 */
4888void
4889xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4890 xmlXPathVariableLookupFunc f, void *data) {
4891 if (ctxt == NULL)
4892 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004893 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00004894 ctxt->varLookupData = data;
4895}
4896
4897/**
4898 * xmlXPathVariableLookup:
4899 * @ctxt: the XPath context
4900 * @name: the variable name
4901 *
4902 * Search in the Variable array of the context for the given
4903 * variable value.
4904 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00004905 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00004906 */
4907xmlXPathObjectPtr
4908xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4909 if (ctxt == NULL)
4910 return(NULL);
4911
4912 if (ctxt->varLookupFunc != NULL) {
4913 xmlXPathObjectPtr ret;
4914
4915 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4916 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00004917 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004918 }
4919 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4920}
4921
4922/**
4923 * xmlXPathVariableLookupNS:
4924 * @ctxt: the XPath context
4925 * @name: the variable name
4926 * @ns_uri: the variable namespace URI
4927 *
4928 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00004929 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00004930 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00004931 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00004932 */
4933xmlXPathObjectPtr
4934xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4935 const xmlChar *ns_uri) {
4936 if (ctxt == NULL)
4937 return(NULL);
4938
4939 if (ctxt->varLookupFunc != NULL) {
4940 xmlXPathObjectPtr ret;
4941
4942 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4943 (ctxt->varLookupData, name, ns_uri);
4944 if (ret != NULL) return(ret);
4945 }
4946
4947 if (ctxt->varHash == NULL)
4948 return(NULL);
4949 if (name == NULL)
4950 return(NULL);
4951
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004952 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
Daniel Veillard8c357d52001-07-03 23:43:33 +00004953 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00004954}
4955
4956/**
4957 * xmlXPathRegisteredVariablesCleanup:
4958 * @ctxt: the XPath context
4959 *
4960 * Cleanup the XPath context data associated to registered variables
4961 */
4962void
4963xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4964 if (ctxt == NULL)
4965 return;
4966
Daniel Veillard76d66f42001-05-16 21:05:17 +00004967 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00004968 ctxt->varHash = NULL;
4969}
4970
4971/**
4972 * xmlXPathRegisterNs:
4973 * @ctxt: the XPath context
4974 * @prefix: the namespace prefix
4975 * @ns_uri: the namespace name
4976 *
4977 * Register a new namespace. If @ns_uri is NULL it unregisters
4978 * the namespace
4979 *
4980 * Returns 0 in case of success, -1 in case of error
4981 */
4982int
4983xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
4984 const xmlChar *ns_uri) {
4985 if (ctxt == NULL)
4986 return(-1);
4987 if (prefix == NULL)
4988 return(-1);
4989
4990 if (ctxt->nsHash == NULL)
4991 ctxt->nsHash = xmlHashCreate(10);
4992 if (ctxt->nsHash == NULL)
4993 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00004994 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00004995 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00004996 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00004997 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00004998 (xmlHashDeallocator)xmlFree));
4999}
5000
5001/**
5002 * xmlXPathNsLookup:
5003 * @ctxt: the XPath context
5004 * @prefix: the namespace prefix value
5005 *
5006 * Search in the namespace declaration array of the context for the given
5007 * namespace name associated to the given prefix
5008 *
5009 * Returns the value or NULL if not found
5010 */
5011const xmlChar *
5012xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5013 if (ctxt == NULL)
5014 return(NULL);
5015 if (prefix == NULL)
5016 return(NULL);
5017
5018#ifdef XML_XML_NAMESPACE
5019 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5020 return(XML_XML_NAMESPACE);
5021#endif
5022
Daniel Veillardc8f620b2001-04-30 20:31:33 +00005023 if (ctxt->namespaces != NULL) {
5024 int i;
5025
5026 for (i = 0;i < ctxt->nsNr;i++) {
5027 if ((ctxt->namespaces[i] != NULL) &&
5028 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5029 return(ctxt->namespaces[i]->href);
5030 }
5031 }
Owen Taylor3473f882001-02-23 17:55:21 +00005032
5033 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5034}
5035
5036/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005037 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00005038 * @ctxt: the XPath context
5039 *
5040 * Cleanup the XPath context data associated to registered variables
5041 */
5042void
5043xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5044 if (ctxt == NULL)
5045 return;
5046
Daniel Veillard42766c02002-08-22 20:52:17 +00005047 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00005048 ctxt->nsHash = NULL;
5049}
5050
5051/************************************************************************
5052 * *
5053 * Routines to handle Values *
5054 * *
5055 ************************************************************************/
5056
William M. Brack08171912003-12-29 02:52:11 +00005057/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005058
5059/**
5060 * xmlXPathNewFloat:
5061 * @val: the double value
5062 *
5063 * Create a new xmlXPathObjectPtr of type double and of value @val
5064 *
5065 * Returns the newly created object.
5066 */
5067xmlXPathObjectPtr
5068xmlXPathNewFloat(double val) {
5069 xmlXPathObjectPtr ret;
5070
5071 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5072 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005073 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005074 return(NULL);
5075 }
5076 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5077 ret->type = XPATH_NUMBER;
5078 ret->floatval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005079#ifdef XP_DEBUG_OBJ_USAGE
5080 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5081#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005082 return(ret);
5083}
5084
5085/**
5086 * xmlXPathNewBoolean:
5087 * @val: the boolean value
5088 *
5089 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5090 *
5091 * Returns the newly created object.
5092 */
5093xmlXPathObjectPtr
5094xmlXPathNewBoolean(int val) {
5095 xmlXPathObjectPtr ret;
5096
5097 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5098 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005099 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005100 return(NULL);
5101 }
5102 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5103 ret->type = XPATH_BOOLEAN;
5104 ret->boolval = (val != 0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005105#ifdef XP_DEBUG_OBJ_USAGE
5106 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5107#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005108 return(ret);
5109}
5110
5111/**
5112 * xmlXPathNewString:
5113 * @val: the xmlChar * value
5114 *
5115 * Create a new xmlXPathObjectPtr of type string and of value @val
5116 *
5117 * Returns the newly created object.
5118 */
5119xmlXPathObjectPtr
5120xmlXPathNewString(const xmlChar *val) {
5121 xmlXPathObjectPtr ret;
5122
5123 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5124 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005125 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005126 return(NULL);
5127 }
5128 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5129 ret->type = XPATH_STRING;
5130 if (val != NULL)
5131 ret->stringval = xmlStrdup(val);
5132 else
5133 ret->stringval = xmlStrdup((const xmlChar *)"");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005134#ifdef XP_DEBUG_OBJ_USAGE
5135 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5136#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005137 return(ret);
5138}
5139
5140/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005141 * xmlXPathWrapString:
5142 * @val: the xmlChar * value
5143 *
5144 * Wraps the @val string into an XPath object.
5145 *
5146 * Returns the newly created object.
5147 */
5148xmlXPathObjectPtr
5149xmlXPathWrapString (xmlChar *val) {
5150 xmlXPathObjectPtr ret;
5151
5152 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5153 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005154 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005155 return(NULL);
5156 }
5157 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5158 ret->type = XPATH_STRING;
5159 ret->stringval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005160#ifdef XP_DEBUG_OBJ_USAGE
5161 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5162#endif
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005163 return(ret);
5164}
5165
5166/**
Owen Taylor3473f882001-02-23 17:55:21 +00005167 * xmlXPathNewCString:
5168 * @val: the char * value
5169 *
5170 * Create a new xmlXPathObjectPtr of type string and of value @val
5171 *
5172 * Returns the newly created object.
5173 */
5174xmlXPathObjectPtr
5175xmlXPathNewCString(const char *val) {
5176 xmlXPathObjectPtr ret;
5177
5178 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5179 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005180 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005181 return(NULL);
5182 }
5183 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5184 ret->type = XPATH_STRING;
5185 ret->stringval = xmlStrdup(BAD_CAST val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005186#ifdef XP_DEBUG_OBJ_USAGE
5187 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5188#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005189 return(ret);
5190}
5191
5192/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005193 * xmlXPathWrapCString:
5194 * @val: the char * value
5195 *
5196 * Wraps a string into an XPath object.
5197 *
5198 * Returns the newly created object.
5199 */
5200xmlXPathObjectPtr
5201xmlXPathWrapCString (char * val) {
5202 return(xmlXPathWrapString((xmlChar *)(val)));
5203}
5204
5205/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005206 * xmlXPathWrapExternal:
5207 * @val: the user data
5208 *
5209 * Wraps the @val data into an XPath object.
5210 *
5211 * Returns the newly created object.
5212 */
5213xmlXPathObjectPtr
5214xmlXPathWrapExternal (void *val) {
5215 xmlXPathObjectPtr ret;
5216
5217 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5218 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005219 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005220 return(NULL);
5221 }
5222 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5223 ret->type = XPATH_USERS;
5224 ret->user = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005225#ifdef XP_DEBUG_OBJ_USAGE
5226 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5227#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005228 return(ret);
5229}
5230
5231/**
Owen Taylor3473f882001-02-23 17:55:21 +00005232 * xmlXPathObjectCopy:
5233 * @val: the original object
5234 *
5235 * allocate a new copy of a given object
5236 *
5237 * Returns the newly created object.
5238 */
5239xmlXPathObjectPtr
5240xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5241 xmlXPathObjectPtr ret;
5242
5243 if (val == NULL)
5244 return(NULL);
5245
5246 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5247 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005248 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005249 return(NULL);
5250 }
5251 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005252#ifdef XP_DEBUG_OBJ_USAGE
5253 xmlXPathDebugObjUsageRequested(NULL, val->type);
5254#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005255 switch (val->type) {
5256 case XPATH_BOOLEAN:
5257 case XPATH_NUMBER:
5258 case XPATH_POINT:
5259 case XPATH_RANGE:
5260 break;
5261 case XPATH_STRING:
5262 ret->stringval = xmlStrdup(val->stringval);
5263 break;
5264 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00005265#if 0
5266/*
5267 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5268 this previous handling is no longer correct, and can cause some serious
5269 problems (ref. bug 145547)
5270*/
Owen Taylor3473f882001-02-23 17:55:21 +00005271 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005272 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005273 xmlNodePtr cur, tmp;
5274 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005275
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005276 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005277 top = xmlNewDoc(NULL);
5278 top->name = (char *)
5279 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005280 ret->user = top;
5281 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005282 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005283 cur = val->nodesetval->nodeTab[0]->children;
5284 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005285 tmp = xmlDocCopyNode(cur, top, 1);
5286 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005287 cur = cur->next;
5288 }
5289 }
William M. Bracke9449c52004-07-11 14:41:20 +00005290
Daniel Veillard9adc0462003-03-24 18:39:54 +00005291 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005292 } else
Owen Taylor3473f882001-02-23 17:55:21 +00005293 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005294 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00005295 break;
William M. Bracke9449c52004-07-11 14:41:20 +00005296#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005297 case XPATH_NODESET:
5298 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005299 /* Do not deallocate the copied tree value */
5300 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005301 break;
5302 case XPATH_LOCATIONSET:
5303#ifdef LIBXML_XPTR_ENABLED
5304 {
5305 xmlLocationSetPtr loc = val->user;
5306 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5307 break;
5308 }
5309#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00005310 case XPATH_USERS:
5311 ret->user = val->user;
5312 break;
5313 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00005314 xmlGenericError(xmlGenericErrorContext,
5315 "xmlXPathObjectCopy: unsupported type %d\n",
5316 val->type);
5317 break;
5318 }
5319 return(ret);
5320}
5321
5322/**
5323 * xmlXPathFreeObject:
5324 * @obj: the object to free
5325 *
5326 * Free up an xmlXPathObjectPtr object.
5327 */
5328void
5329xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5330 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005331 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00005332 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00005333#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005334 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005335 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00005336 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00005337 } else
5338#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005339 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
William M. Bracke9449c52004-07-11 14:41:20 +00005340 if (obj->nodesetval != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005341 xmlXPathFreeValueTree(obj->nodesetval);
Daniel Veillard77851712001-02-27 21:54:07 +00005342 } else {
5343 if (obj->nodesetval != NULL)
5344 xmlXPathFreeNodeSet(obj->nodesetval);
5345 }
Owen Taylor3473f882001-02-23 17:55:21 +00005346#ifdef LIBXML_XPTR_ENABLED
5347 } else if (obj->type == XPATH_LOCATIONSET) {
5348 if (obj->user != NULL)
5349 xmlXPtrFreeLocationSet(obj->user);
5350#endif
5351 } else if (obj->type == XPATH_STRING) {
5352 if (obj->stringval != NULL)
5353 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005354 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005355#ifdef XP_DEBUG_OBJ_USAGE
5356 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5357#endif
5358 xmlFree(obj);
5359}
Owen Taylor3473f882001-02-23 17:55:21 +00005360
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005361/**
5362 * xmlXPathReleaseObject:
5363 * @obj: the xmlXPathObjectPtr to free or to cache
5364 *
5365 * Depending on the state of the cache this frees the given
5366 * XPath object or stores it in the cache.
5367 */
5368static void
5369xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5370{
5371#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5372 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5373 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5374
5375#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5376
5377 if (obj == NULL)
5378 return;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005379 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005380 xmlXPathFreeObject(obj);
5381 } else {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005382 xmlXPathContextCachePtr cache =
5383 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005384
5385 switch (obj->type) {
5386 case XPATH_NODESET:
5387 case XPATH_XSLT_TREE:
5388 if (obj->nodesetval != NULL) {
5389 if (obj->boolval) {
5390 /*
5391 * It looks like the @boolval is used for
5392 * evaluation if this an XSLT Result Tree Fragment.
5393 * TODO: Check if this assumption is correct.
5394 */
5395 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5396 xmlXPathFreeValueTree(obj->nodesetval);
5397 obj->nodesetval = NULL;
5398 } else if ((obj->nodesetval->nodeMax <= 40) &&
5399 (XP_CACHE_WANTS(cache->nodesetObjs,
5400 cache->maxNodeset)))
5401 {
5402 XP_CACHE_ADD(cache->nodesetObjs, obj);
5403 goto obj_cached;
5404 } else {
5405 xmlXPathFreeNodeSet(obj->nodesetval);
5406 obj->nodesetval = NULL;
5407 }
5408 }
5409 break;
5410 case XPATH_STRING:
5411 if (obj->stringval != NULL)
5412 xmlFree(obj->stringval);
5413
5414 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5415 XP_CACHE_ADD(cache->stringObjs, obj);
5416 goto obj_cached;
5417 }
5418 break;
5419 case XPATH_BOOLEAN:
5420 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5421 XP_CACHE_ADD(cache->booleanObjs, obj);
5422 goto obj_cached;
5423 }
5424 break;
5425 case XPATH_NUMBER:
5426 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5427 XP_CACHE_ADD(cache->numberObjs, obj);
5428 goto obj_cached;
5429 }
5430 break;
5431#ifdef LIBXML_XPTR_ENABLED
5432 case XPATH_LOCATIONSET:
5433 if (obj->user != NULL) {
5434 xmlXPtrFreeLocationSet(obj->user);
5435 }
5436 goto free_obj;
5437#endif
5438 default:
5439 goto free_obj;
5440 }
5441
5442 /*
5443 * Fallback to adding to the misc-objects slot.
5444 */
5445 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5446 XP_CACHE_ADD(cache->miscObjs, obj);
5447 } else
5448 goto free_obj;
5449
5450obj_cached:
5451
5452#ifdef XP_DEBUG_OBJ_USAGE
5453 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5454#endif
5455
5456 if (obj->nodesetval != NULL) {
5457 xmlNodeSetPtr tmpset = obj->nodesetval;
5458
5459 /*
5460 * TODO: Due to those nasty ns-nodes, we need to traverse
5461 * the list and free the ns-nodes.
5462 * URGENT TODO: Check if it's actually slowing things down.
5463 * Maybe we shouldn't try to preserve the list.
5464 */
5465 if (tmpset->nodeNr > 1) {
5466 int i;
5467 xmlNodePtr node;
5468
5469 for (i = 0; i < tmpset->nodeNr; i++) {
5470 node = tmpset->nodeTab[i];
5471 if ((node != NULL) &&
5472 (node->type == XML_NAMESPACE_DECL))
5473 {
5474 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5475 }
5476 }
5477 } else if (tmpset->nodeNr == 1) {
5478 if ((tmpset->nodeTab[0] != NULL) &&
5479 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5480 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5481 }
5482 tmpset->nodeNr = 0;
5483 memset(obj, 0, sizeof(xmlXPathObject));
5484 obj->nodesetval = tmpset;
5485 } else
5486 memset(obj, 0, sizeof(xmlXPathObject));
5487
5488 return;
5489
5490free_obj:
5491 /*
5492 * Cache is full; free the object.
5493 */
5494 if (obj->nodesetval != NULL)
5495 xmlXPathFreeNodeSet(obj->nodesetval);
5496#ifdef XP_DEBUG_OBJ_USAGE
5497 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5498#endif
5499 xmlFree(obj);
5500 }
5501 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005502}
5503
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005504
5505/************************************************************************
5506 * *
5507 * Type Casting Routines *
5508 * *
5509 ************************************************************************/
5510
5511/**
5512 * xmlXPathCastBooleanToString:
5513 * @val: a boolean
5514 *
5515 * Converts a boolean to its string value.
5516 *
5517 * Returns a newly allocated string.
5518 */
5519xmlChar *
5520xmlXPathCastBooleanToString (int val) {
5521 xmlChar *ret;
5522 if (val)
5523 ret = xmlStrdup((const xmlChar *) "true");
5524 else
5525 ret = xmlStrdup((const xmlChar *) "false");
5526 return(ret);
5527}
5528
5529/**
5530 * xmlXPathCastNumberToString:
5531 * @val: a number
5532 *
5533 * Converts a number to its string value.
5534 *
5535 * Returns a newly allocated string.
5536 */
5537xmlChar *
5538xmlXPathCastNumberToString (double val) {
5539 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00005540 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005541 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005542 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005543 break;
5544 case -1:
5545 ret = xmlStrdup((const xmlChar *) "-Infinity");
5546 break;
5547 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00005548 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005549 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005550 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5551 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005552 } else {
5553 /* could be improved */
5554 char buf[100];
Daniel Veillard11ce4002006-03-10 00:36:23 +00005555 xmlXPathFormatNumber(val, buf, 99);
5556 buf[99] = 0;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005557 ret = xmlStrdup((const xmlChar *) buf);
5558 }
5559 }
5560 return(ret);
5561}
5562
5563/**
5564 * xmlXPathCastNodeToString:
5565 * @node: a node
5566 *
5567 * Converts a node to its string value.
5568 *
5569 * Returns a newly allocated string.
5570 */
5571xmlChar *
5572xmlXPathCastNodeToString (xmlNodePtr node) {
5573 return(xmlNodeGetContent(node));
5574}
5575
5576/**
5577 * xmlXPathCastNodeSetToString:
5578 * @ns: a node-set
5579 *
5580 * Converts a node-set to its string value.
5581 *
5582 * Returns a newly allocated string.
5583 */
5584xmlChar *
5585xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5586 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5587 return(xmlStrdup((const xmlChar *) ""));
5588
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00005589 if (ns->nodeNr > 1)
5590 xmlXPathNodeSetSort(ns);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005591 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5592}
5593
5594/**
5595 * xmlXPathCastToString:
5596 * @val: an XPath object
5597 *
5598 * Converts an existing object to its string() equivalent
5599 *
Kasimier T. Buchcik50128ad2006-08-15 13:04:07 +00005600 * Returns the allocated string value of the object, NULL in case of error.
5601 * It's up to the caller to free the string memory with xmlFree().
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005602 */
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. Buchcik324c75b2006-06-29 10:31:35 +000011545 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011546
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. Buchcik324c75b2006-06-29 10:31:35 +000011691 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011692
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) {
Kasimier T. Buchcik889b7622006-07-03 11:44:13 +000012197 if (type == XML_NAMESPACE_DECL)
12198 XP_TEST_HIT_NS
12199 else
12200 XP_TEST_HIT
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012201 } else if ((type == NODE_TYPE_TEXT) &&
12202 (cur->type == XML_CDATA_SECTION_NODE))
12203 {
12204 XP_TEST_HIT
12205 }
12206 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012207 case NODE_TEST_PI:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012208 if ((cur->type == XML_PI_NODE) &&
12209 ((name == NULL) || xmlStrEqual(name, cur->name)))
12210 {
12211 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012212 }
12213 break;
12214 case NODE_TEST_ALL:
12215 if (axis == AXIS_ATTRIBUTE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012216 if (cur->type == XML_ATTRIBUTE_NODE)
12217 {
12218 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012219 }
12220 } else if (axis == AXIS_NAMESPACE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012221 if (cur->type == XML_NAMESPACE_DECL)
12222 {
12223 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012224 }
12225 } else {
12226 if (cur->type == XML_ELEMENT_NODE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012227 if (prefix == NULL)
12228 {
12229 XP_TEST_HIT
12230
Daniel Veillardf06307e2001-07-03 10:35:50 +000012231 } else if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012232 (xmlStrEqual(URI, cur->ns->href)))
12233 {
12234 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012235 }
12236 }
12237 }
12238 break;
12239 case NODE_TEST_NS:{
12240 TODO;
12241 break;
12242 }
12243 case NODE_TEST_NAME:
12244 switch (cur->type) {
12245 case XML_ELEMENT_NODE:
12246 if (xmlStrEqual(name, cur->name)) {
12247 if (prefix == NULL) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012248 if (cur->ns == NULL)
12249 {
12250 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012251 }
12252 } else {
12253 if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012254 (xmlStrEqual(URI, cur->ns->href)))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012255 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012256 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012257 }
12258 }
12259 }
12260 break;
12261 case XML_ATTRIBUTE_NODE:{
12262 xmlAttrPtr attr = (xmlAttrPtr) cur;
12263
12264 if (xmlStrEqual(name, attr->name)) {
12265 if (prefix == NULL) {
12266 if ((attr->ns == NULL) ||
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012267 (attr->ns->prefix == NULL))
12268 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012269 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012270 }
12271 } else {
12272 if ((attr->ns != NULL) &&
12273 (xmlStrEqual(URI,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012274 attr->ns->href)))
12275 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012276 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012277 }
12278 }
12279 }
12280 break;
12281 }
12282 case XML_NAMESPACE_DECL:
12283 if (cur->type == XML_NAMESPACE_DECL) {
12284 xmlNsPtr ns = (xmlNsPtr) cur;
12285
12286 if ((ns->prefix != NULL) && (name != NULL)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012287 && (xmlStrEqual(ns->prefix, name)))
12288 {
12289 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012290 }
12291 }
12292 break;
12293 default:
12294 break;
12295 }
12296 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012297 } /* switch(test) */
12298 } while (cur != NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012299
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012300 goto apply_predicates;
12301
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012302axis_range_end: /* ----------------------------------------------------- */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012303 /*
12304 * We have a "/foo[n]", and position() = n was reached.
12305 * Note that we can have as well "/foo/::parent::foo[1]", so
12306 * a duplicate-aware merge is still needed.
12307 * Merge with the result.
12308 */
12309 if (outSeq == NULL) {
12310 outSeq = seq;
12311 seq = NULL;
12312 } else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012313 outSeq = mergeAndClear(outSeq, seq, 0);
12314 /*
12315 * Break if only a true/false result was requested.
12316 */
12317 if (toBool)
12318 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012319 continue;
12320
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012321first_hit: /* ---------------------------------------------------------- */
12322 /*
12323 * Break if only a true/false result was requested and
12324 * no predicates existed and a node test succeeded.
12325 */
12326 if (outSeq == NULL) {
12327 outSeq = seq;
12328 seq = NULL;
12329 } else
12330 outSeq = mergeAndClear(outSeq, seq, 0);
12331 break;
12332
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012333#ifdef DEBUG_STEP
12334 if (seq != NULL)
12335 nbMatches += seq->nodeNr;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012336#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012337
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012338apply_predicates: /* --------------------------------------------------- */
12339 /*
12340 * Apply predicates.
12341 */
12342 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12343 /*
12344 * E.g. when we have a "/foo[some expression][n]".
12345 */
12346 /*
12347 * QUESTION TODO: The old predicate evaluation took into
12348 * account location-sets.
12349 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12350 * Do we expect such a set here?
12351 * All what I learned now from the evaluation semantics
12352 * does not indicate that a location-set will be processed
12353 * here, so this looks OK.
12354 */
12355 /*
12356 * Iterate over all predicates, starting with the outermost
12357 * predicate.
12358 * TODO: Problem: we cannot execute the inner predicates first
12359 * since we cannot go back *up* the operator tree!
12360 * Options we have:
12361 * 1) Use of recursive functions (like is it currently done
12362 * via xmlXPathCompOpEval())
12363 * 2) Add a predicate evaluation information stack to the
12364 * context struct
12365 * 3) Change the way the operators are linked; we need a
12366 * "parent" field on xmlXPathStepOp
12367 *
12368 * For the moment, I'll try to solve this with a recursive
12369 * function: xmlXPathCompOpEvalPredicate().
12370 */
12371 size = seq->nodeNr;
12372 if (hasPredicateRange != 0)
12373 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12374 predOp, seq, size, maxPos, maxPos, hasNsNodes);
12375 else
12376 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12377 predOp, seq, size, hasNsNodes);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012378
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012379 if (ctxt->error != XPATH_EXPRESSION_OK) {
12380 total = 0;
12381 goto error;
12382 }
12383 /*
12384 * Add the filtered set of nodes to the result node set.
12385 */
12386 if (newSize == 0) {
12387 /*
12388 * The predicates filtered all nodes out.
12389 */
12390 xmlXPathNodeSetClear(seq, hasNsNodes);
12391 } else if (seq->nodeNr > 0) {
12392 /*
12393 * Add to result set.
12394 */
12395 if (outSeq == NULL) {
12396 if (size != newSize) {
12397 /*
12398 * We need to merge and clear here, since
12399 * the sequence will contained NULLed entries.
12400 */
12401 outSeq = mergeAndClear(NULL, seq, 1);
12402 } else {
12403 outSeq = seq;
12404 seq = NULL;
12405 }
12406 } else
12407 outSeq = mergeAndClear(outSeq, seq,
12408 (size != newSize) ? 1: 0);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012409 /*
12410 * Break if only a true/false result was requested.
12411 */
12412 if (toBool)
12413 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012414 }
12415 } else if (seq->nodeNr > 0) {
12416 /*
12417 * Add to result set.
12418 */
12419 if (outSeq == NULL) {
12420 outSeq = seq;
12421 seq = NULL;
12422 } else {
12423 outSeq = mergeAndClear(outSeq, seq, 0);
12424 }
12425 }
12426 }
12427
12428error:
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012429 if ((obj->boolval) && (obj->user != NULL)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012430 /*
12431 * QUESTION TODO: What does this do and why?
12432 * TODO: Do we have to do this also for the "error"
12433 * cleanup further down?
12434 */
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012435 ctxt->value->boolval = 1;
12436 ctxt->value->user = obj->user;
12437 obj->user = NULL;
12438 obj->boolval = 0;
12439 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012440 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012441
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012442 /*
12443 * Ensure we return at least an emtpy set.
12444 */
12445 if (outSeq == NULL) {
12446 if ((seq != NULL) && (seq->nodeNr == 0))
12447 outSeq = seq;
12448 else
12449 outSeq = xmlXPathNodeSetCreate(NULL);
12450 }
12451 if ((seq != NULL) && (seq != outSeq)) {
12452 xmlXPathFreeNodeSet(seq);
12453 }
12454 /*
12455 * Hand over the result. Better to push the set also in
12456 * case of errors.
12457 */
12458 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12459 /*
12460 * Reset the context node.
12461 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012462 xpctxt->node = oldContextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012463
12464#ifdef DEBUG_STEP
12465 xmlGenericError(xmlGenericErrorContext,
12466 "\nExamined %d nodes, found %d nodes at that step\n",
12467 total, nbMatches);
12468#endif
12469
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012470 return(total);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012471}
12472
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012473static int
12474xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12475 xmlXPathStepOpPtr op, xmlNodePtr * first);
12476
Daniel Veillardf06307e2001-07-03 10:35:50 +000012477/**
12478 * xmlXPathCompOpEvalFirst:
12479 * @ctxt: the XPath parser context with the compiled expression
12480 * @op: an XPath compiled operation
12481 * @first: the first elem found so far
12482 *
12483 * Evaluate the Precompiled XPath operation searching only the first
12484 * element in document order
12485 *
12486 * Returns the number of examined objects.
12487 */
12488static int
12489xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12490 xmlXPathStepOpPtr op, xmlNodePtr * first)
12491{
12492 int total = 0, cur;
12493 xmlXPathCompExprPtr comp;
12494 xmlXPathObjectPtr arg1, arg2;
12495
Daniel Veillard556c6682001-10-06 09:59:51 +000012496 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012497 comp = ctxt->comp;
12498 switch (op->op) {
12499 case XPATH_OP_END:
12500 return (0);
12501 case XPATH_OP_UNION:
12502 total =
12503 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12504 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012505 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012506 if ((ctxt->value != NULL)
12507 && (ctxt->value->type == XPATH_NODESET)
12508 && (ctxt->value->nodesetval != NULL)
12509 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12510 /*
12511 * limit tree traversing to first node in the result
12512 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012513 /*
12514 * OPTIMIZE TODO: This implicitely sorts
12515 * the result, even if not needed. E.g. if the argument
12516 * of the count() function, no sorting is needed.
12517 * OPTIMIZE TODO: How do we know if the node-list wasn't
12518 * aready sorted?
12519 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012520 if (ctxt->value->nodesetval->nodeNr > 1)
12521 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012522 *first = ctxt->value->nodesetval->nodeTab[0];
12523 }
12524 cur =
12525 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12526 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012527 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012528 CHECK_TYPE0(XPATH_NODESET);
12529 arg2 = valuePop(ctxt);
12530
12531 CHECK_TYPE0(XPATH_NODESET);
12532 arg1 = valuePop(ctxt);
12533
12534 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12535 arg2->nodesetval);
12536 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012537 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012538 /* optimizer */
12539 if (total > cur)
12540 xmlXPathCompSwap(op);
12541 return (total + cur);
12542 case XPATH_OP_ROOT:
12543 xmlXPathRoot(ctxt);
12544 return (0);
12545 case XPATH_OP_NODE:
12546 if (op->ch1 != -1)
12547 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012548 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012549 if (op->ch2 != -1)
12550 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012551 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012552 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12553 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012554 return (total);
12555 case XPATH_OP_RESET:
12556 if (op->ch1 != -1)
12557 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012558 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012559 if (op->ch2 != -1)
12560 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012561 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012562 ctxt->context->node = NULL;
12563 return (total);
12564 case XPATH_OP_COLLECT:{
12565 if (op->ch1 == -1)
12566 return (total);
12567
12568 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012569 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012570
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012571 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012572 return (total);
12573 }
12574 case XPATH_OP_VALUE:
12575 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012576 xmlXPathCacheObjectCopy(ctxt->context,
12577 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012578 return (0);
12579 case XPATH_OP_SORT:
12580 if (op->ch1 != -1)
12581 total +=
12582 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12583 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012584 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012585 if ((ctxt->value != NULL)
12586 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012587 && (ctxt->value->nodesetval != NULL)
12588 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012589 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12590 return (total);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012591#ifdef XP_OPTIMIZED_FILTER_FIRST
12592 case XPATH_OP_FILTER:
12593 total =+ xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12594 return (total);
12595#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000012596 default:
12597 return (xmlXPathCompOpEval(ctxt, op));
12598 }
12599}
12600
12601/**
12602 * xmlXPathCompOpEvalLast:
12603 * @ctxt: the XPath parser context with the compiled expression
12604 * @op: an XPath compiled operation
12605 * @last: the last elem found so far
12606 *
12607 * Evaluate the Precompiled XPath operation searching only the last
12608 * element in document order
12609 *
William M. Brack08171912003-12-29 02:52:11 +000012610 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000012611 */
12612static int
12613xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12614 xmlNodePtr * last)
12615{
12616 int total = 0, cur;
12617 xmlXPathCompExprPtr comp;
12618 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +000012619 xmlNodePtr bak;
12620 xmlDocPtr bakd;
12621 int pp;
12622 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012623
Daniel Veillard556c6682001-10-06 09:59:51 +000012624 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012625 comp = ctxt->comp;
12626 switch (op->op) {
12627 case XPATH_OP_END:
12628 return (0);
12629 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +000012630 bakd = ctxt->context->doc;
12631 bak = ctxt->context->node;
12632 pp = ctxt->context->proximityPosition;
12633 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012634 total =
12635 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012636 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012637 if ((ctxt->value != NULL)
12638 && (ctxt->value->type == XPATH_NODESET)
12639 && (ctxt->value->nodesetval != NULL)
12640 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12641 /*
12642 * limit tree traversing to first node in the result
12643 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012644 if (ctxt->value->nodesetval->nodeNr > 1)
12645 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012646 *last =
12647 ctxt->value->nodesetval->nodeTab[ctxt->value->
12648 nodesetval->nodeNr -
12649 1];
12650 }
William M. Brackce4fc562004-01-22 02:47:18 +000012651 ctxt->context->doc = bakd;
12652 ctxt->context->node = bak;
12653 ctxt->context->proximityPosition = pp;
12654 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012655 cur =
12656 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012657 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012658 if ((ctxt->value != NULL)
12659 && (ctxt->value->type == XPATH_NODESET)
12660 && (ctxt->value->nodesetval != NULL)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012661 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012662 }
12663 CHECK_TYPE0(XPATH_NODESET);
12664 arg2 = valuePop(ctxt);
12665
12666 CHECK_TYPE0(XPATH_NODESET);
12667 arg1 = valuePop(ctxt);
12668
12669 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12670 arg2->nodesetval);
12671 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012672 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012673 /* optimizer */
12674 if (total > cur)
12675 xmlXPathCompSwap(op);
12676 return (total + cur);
12677 case XPATH_OP_ROOT:
12678 xmlXPathRoot(ctxt);
12679 return (0);
12680 case XPATH_OP_NODE:
12681 if (op->ch1 != -1)
12682 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012683 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012684 if (op->ch2 != -1)
12685 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012686 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012687 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12688 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012689 return (total);
12690 case XPATH_OP_RESET:
12691 if (op->ch1 != -1)
12692 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012693 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012694 if (op->ch2 != -1)
12695 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012696 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012697 ctxt->context->node = NULL;
12698 return (total);
12699 case XPATH_OP_COLLECT:{
12700 if (op->ch1 == -1)
12701 return (0);
12702
12703 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012704 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012705
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012706 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012707 return (total);
12708 }
12709 case XPATH_OP_VALUE:
12710 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012711 xmlXPathCacheObjectCopy(ctxt->context,
12712 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012713 return (0);
12714 case XPATH_OP_SORT:
12715 if (op->ch1 != -1)
12716 total +=
12717 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12718 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012719 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012720 if ((ctxt->value != NULL)
12721 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012722 && (ctxt->value->nodesetval != NULL)
12723 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012724 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12725 return (total);
12726 default:
12727 return (xmlXPathCompOpEval(ctxt, op));
12728 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012729}
12730
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012731#ifdef XP_OPTIMIZED_FILTER_FIRST
12732static int
12733xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12734 xmlXPathStepOpPtr op, xmlNodePtr * first)
12735{
12736 int total = 0;
12737 xmlXPathCompExprPtr comp;
12738 xmlXPathObjectPtr res;
12739 xmlXPathObjectPtr obj;
12740 xmlNodeSetPtr oldset;
12741 xmlNodePtr oldnode;
12742 xmlDocPtr oldDoc;
12743 int i;
12744
12745 CHECK_ERROR0;
12746 comp = ctxt->comp;
12747 /*
12748 * Optimization for ()[last()] selection i.e. the last elem
12749 */
12750 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12751 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12752 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12753 int f = comp->steps[op->ch2].ch1;
12754
12755 if ((f != -1) &&
12756 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12757 (comp->steps[f].value5 == NULL) &&
12758 (comp->steps[f].value == 0) &&
12759 (comp->steps[f].value4 != NULL) &&
12760 (xmlStrEqual
12761 (comp->steps[f].value4, BAD_CAST "last"))) {
12762 xmlNodePtr last = NULL;
12763
12764 total +=
12765 xmlXPathCompOpEvalLast(ctxt,
12766 &comp->steps[op->ch1],
12767 &last);
12768 CHECK_ERROR0;
12769 /*
12770 * The nodeset should be in document order,
12771 * Keep only the last value
12772 */
12773 if ((ctxt->value != NULL) &&
12774 (ctxt->value->type == XPATH_NODESET) &&
12775 (ctxt->value->nodesetval != NULL) &&
12776 (ctxt->value->nodesetval->nodeTab != NULL) &&
12777 (ctxt->value->nodesetval->nodeNr > 1)) {
12778 ctxt->value->nodesetval->nodeTab[0] =
12779 ctxt->value->nodesetval->nodeTab[ctxt->
12780 value->
12781 nodesetval->
12782 nodeNr -
12783 1];
12784 ctxt->value->nodesetval->nodeNr = 1;
12785 *first = *(ctxt->value->nodesetval->nodeTab);
12786 }
12787 return (total);
12788 }
12789 }
12790
12791 if (op->ch1 != -1)
12792 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12793 CHECK_ERROR0;
12794 if (op->ch2 == -1)
12795 return (total);
12796 if (ctxt->value == NULL)
12797 return (total);
12798
12799#ifdef LIBXML_XPTR_ENABLED
12800 oldnode = ctxt->context->node;
12801 /*
12802 * Hum are we filtering the result of an XPointer expression
12803 */
12804 if (ctxt->value->type == XPATH_LOCATIONSET) {
12805 xmlXPathObjectPtr tmp = NULL;
12806 xmlLocationSetPtr newlocset = NULL;
12807 xmlLocationSetPtr oldlocset;
12808
12809 /*
12810 * Extract the old locset, and then evaluate the result of the
12811 * expression for all the element in the locset. use it to grow
12812 * up a new locset.
12813 */
12814 CHECK_TYPE0(XPATH_LOCATIONSET);
12815 obj = valuePop(ctxt);
12816 oldlocset = obj->user;
12817 ctxt->context->node = NULL;
12818
12819 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12820 ctxt->context->contextSize = 0;
12821 ctxt->context->proximityPosition = 0;
12822 if (op->ch2 != -1)
12823 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12824 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012825 if (res != NULL) {
12826 xmlXPathReleaseObject(ctxt->context, res);
12827 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012828 valuePush(ctxt, obj);
12829 CHECK_ERROR0;
12830 return (total);
12831 }
12832 newlocset = xmlXPtrLocationSetCreate(NULL);
12833
12834 for (i = 0; i < oldlocset->locNr; i++) {
12835 /*
12836 * Run the evaluation with a node list made of a
12837 * single item in the nodelocset.
12838 */
12839 ctxt->context->node = oldlocset->locTab[i]->user;
12840 ctxt->context->contextSize = oldlocset->locNr;
12841 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012842 if (tmp == NULL) {
12843 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12844 ctxt->context->node);
12845 } else {
12846 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12847 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012848 }
12849 valuePush(ctxt, tmp);
12850 if (op->ch2 != -1)
12851 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12852 if (ctxt->error != XPATH_EXPRESSION_OK) {
12853 xmlXPathFreeObject(obj);
12854 return(0);
12855 }
12856 /*
12857 * The result of the evaluation need to be tested to
12858 * decided whether the filter succeeded or not
12859 */
12860 res = valuePop(ctxt);
12861 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12862 xmlXPtrLocationSetAdd(newlocset,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012863 xmlXPathCacheObjectCopy(ctxt->context,
12864 oldlocset->locTab[i]));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012865 }
12866 /*
12867 * Cleanup
12868 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012869 if (res != NULL) {
12870 xmlXPathReleaseObject(ctxt->context, res);
12871 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012872 if (ctxt->value == tmp) {
12873 valuePop(ctxt);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012874 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012875 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012876 * REVISIT TODO: Don't create a temporary nodeset
12877 * for everly iteration.
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012878 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012879 /* OLD: xmlXPathFreeObject(res); */
12880 } else
12881 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012882 ctxt->context->node = NULL;
12883 /*
12884 * Only put the first node in the result, then leave.
12885 */
12886 if (newlocset->locNr > 0) {
12887 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
12888 break;
12889 }
12890 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012891 if (tmp != NULL) {
12892 xmlXPathReleaseObject(ctxt->context, tmp);
12893 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012894 /*
12895 * The result is used as the new evaluation locset.
12896 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012897 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012898 ctxt->context->node = NULL;
12899 ctxt->context->contextSize = -1;
12900 ctxt->context->proximityPosition = -1;
12901 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12902 ctxt->context->node = oldnode;
12903 return (total);
12904 }
12905#endif /* LIBXML_XPTR_ENABLED */
12906
12907 /*
12908 * Extract the old set, and then evaluate the result of the
12909 * expression for all the element in the set. use it to grow
12910 * up a new set.
12911 */
12912 CHECK_TYPE0(XPATH_NODESET);
12913 obj = valuePop(ctxt);
12914 oldset = obj->nodesetval;
12915
12916 oldnode = ctxt->context->node;
12917 oldDoc = ctxt->context->doc;
12918 ctxt->context->node = NULL;
12919
12920 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
12921 ctxt->context->contextSize = 0;
12922 ctxt->context->proximityPosition = 0;
12923 /* QUESTION TODO: Why was this code commented out?
12924 if (op->ch2 != -1)
12925 total +=
12926 xmlXPathCompOpEval(ctxt,
12927 &comp->steps[op->ch2]);
12928 CHECK_ERROR0;
12929 res = valuePop(ctxt);
12930 if (res != NULL)
12931 xmlXPathFreeObject(res);
12932 */
12933 valuePush(ctxt, obj);
12934 ctxt->context->node = oldnode;
12935 CHECK_ERROR0;
12936 } else {
12937 xmlNodeSetPtr newset;
12938 xmlXPathObjectPtr tmp = NULL;
12939 /*
12940 * Initialize the new set.
12941 * Also set the xpath document in case things like
12942 * key() evaluation are attempted on the predicate
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012943 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012944 newset = xmlXPathNodeSetCreate(NULL);
12945
12946 for (i = 0; i < oldset->nodeNr; i++) {
12947 /*
12948 * Run the evaluation with a node list made of
12949 * a single item in the nodeset.
12950 */
12951 ctxt->context->node = oldset->nodeTab[i];
12952 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
12953 (oldset->nodeTab[i]->doc != NULL))
12954 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012955 if (tmp == NULL) {
12956 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12957 ctxt->context->node);
12958 } else {
12959 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12960 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012961 }
12962 valuePush(ctxt, tmp);
12963 ctxt->context->contextSize = oldset->nodeNr;
12964 ctxt->context->proximityPosition = i + 1;
12965 if (op->ch2 != -1)
12966 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12967 if (ctxt->error != XPATH_EXPRESSION_OK) {
12968 xmlXPathFreeNodeSet(newset);
12969 xmlXPathFreeObject(obj);
12970 return(0);
12971 }
12972 /*
12973 * The result of the evaluation needs to be tested to
12974 * decide whether the filter succeeded or not
12975 */
12976 res = valuePop(ctxt);
12977 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12978 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
12979 }
12980 /*
12981 * Cleanup
12982 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012983 if (res != NULL) {
12984 xmlXPathReleaseObject(ctxt->context, res);
12985 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012986 if (ctxt->value == tmp) {
12987 valuePop(ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012988 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012989 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012990 * in order to avoid massive recreation inside this
12991 * loop.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012992 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012993 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012994 } else
12995 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012996 ctxt->context->node = NULL;
12997 /*
12998 * Only put the first node in the result, then leave.
12999 */
13000 if (newset->nodeNr > 0) {
13001 *first = *(newset->nodeTab);
13002 break;
13003 }
13004 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013005 if (tmp != NULL) {
13006 xmlXPathReleaseObject(ctxt->context, tmp);
13007 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013008 /*
13009 * The result is used as the new evaluation set.
13010 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013011 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013012 ctxt->context->node = NULL;
13013 ctxt->context->contextSize = -1;
13014 ctxt->context->proximityPosition = -1;
13015 /* may want to move this past the '}' later */
13016 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013017 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013018 }
13019 ctxt->context->node = oldnode;
13020 return(total);
13021}
13022#endif /* XP_OPTIMIZED_FILTER_FIRST */
13023
Owen Taylor3473f882001-02-23 17:55:21 +000013024/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013025 * xmlXPathCompOpEval:
13026 * @ctxt: the XPath parser context with the compiled expression
13027 * @op: an XPath compiled operation
13028 *
13029 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000013030 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013031 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013032static int
13033xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13034{
13035 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013036 int equal, ret;
13037 xmlXPathCompExprPtr comp;
13038 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013039 xmlNodePtr bak;
13040 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000013041 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000013042 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013043
Daniel Veillard556c6682001-10-06 09:59:51 +000013044 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013045 comp = ctxt->comp;
13046 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013047 case XPATH_OP_END:
13048 return (0);
13049 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013050 bakd = ctxt->context->doc;
13051 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013052 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013053 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013054 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013055 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013056 xmlXPathBooleanFunction(ctxt, 1);
13057 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13058 return (total);
13059 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013060 ctxt->context->doc = bakd;
13061 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013062 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013063 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013064 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013065 if (ctxt->error) {
13066 xmlXPathFreeObject(arg2);
13067 return(0);
13068 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013069 xmlXPathBooleanFunction(ctxt, 1);
13070 arg1 = valuePop(ctxt);
13071 arg1->boolval &= arg2->boolval;
13072 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013073 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013074 return (total);
13075 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013076 bakd = ctxt->context->doc;
13077 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013078 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013079 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013080 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013081 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013082 xmlXPathBooleanFunction(ctxt, 1);
13083 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13084 return (total);
13085 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013086 ctxt->context->doc = bakd;
13087 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013088 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013089 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013090 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013091 if (ctxt->error) {
13092 xmlXPathFreeObject(arg2);
13093 return(0);
13094 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013095 xmlXPathBooleanFunction(ctxt, 1);
13096 arg1 = valuePop(ctxt);
13097 arg1->boolval |= arg2->boolval;
13098 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013099 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013100 return (total);
13101 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013102 bakd = ctxt->context->doc;
13103 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013104 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013105 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013106 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013107 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013108 ctxt->context->doc = bakd;
13109 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013110 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013111 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013112 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013113 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000013114 if (op->value)
13115 equal = xmlXPathEqualValues(ctxt);
13116 else
13117 equal = xmlXPathNotEqualValues(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013118 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013119 return (total);
13120 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013121 bakd = ctxt->context->doc;
13122 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013123 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013124 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013125 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013126 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013127 ctxt->context->doc = bakd;
13128 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013129 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013130 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013131 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013132 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013133 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013134 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013135 return (total);
13136 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013137 bakd = ctxt->context->doc;
13138 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013139 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013140 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013141 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013142 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013143 if (op->ch2 != -1) {
13144 ctxt->context->doc = bakd;
13145 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013146 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013147 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013148 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013149 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013150 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013151 if (op->value == 0)
13152 xmlXPathSubValues(ctxt);
13153 else if (op->value == 1)
13154 xmlXPathAddValues(ctxt);
13155 else if (op->value == 2)
13156 xmlXPathValueFlipSign(ctxt);
13157 else if (op->value == 3) {
13158 CAST_TO_NUMBER;
13159 CHECK_TYPE0(XPATH_NUMBER);
13160 }
13161 return (total);
13162 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013163 bakd = ctxt->context->doc;
13164 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013165 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013166 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013167 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013168 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013169 ctxt->context->doc = bakd;
13170 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013171 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013172 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013173 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013174 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013175 if (op->value == 0)
13176 xmlXPathMultValues(ctxt);
13177 else if (op->value == 1)
13178 xmlXPathDivValues(ctxt);
13179 else if (op->value == 2)
13180 xmlXPathModValues(ctxt);
13181 return (total);
13182 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013183 bakd = ctxt->context->doc;
13184 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013185 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013186 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013187 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013188 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013189 ctxt->context->doc = bakd;
13190 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013191 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013192 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013193 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013194 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013195 CHECK_TYPE0(XPATH_NODESET);
13196 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013197
Daniel Veillardf06307e2001-07-03 10:35:50 +000013198 CHECK_TYPE0(XPATH_NODESET);
13199 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013200
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013201 if ((arg1->nodesetval == NULL) ||
13202 ((arg2->nodesetval != NULL) &&
13203 (arg2->nodesetval->nodeNr != 0)))
13204 {
13205 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13206 arg2->nodesetval);
13207 }
13208
Daniel Veillardf06307e2001-07-03 10:35:50 +000013209 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013210 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013211 return (total);
13212 case XPATH_OP_ROOT:
13213 xmlXPathRoot(ctxt);
13214 return (total);
13215 case XPATH_OP_NODE:
13216 if (op->ch1 != -1)
13217 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013218 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013219 if (op->ch2 != -1)
13220 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013221 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013222 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13223 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013224 return (total);
13225 case XPATH_OP_RESET:
13226 if (op->ch1 != -1)
13227 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013228 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013229 if (op->ch2 != -1)
13230 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013231 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013232 ctxt->context->node = NULL;
13233 return (total);
13234 case XPATH_OP_COLLECT:{
13235 if (op->ch1 == -1)
13236 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000013237
Daniel Veillardf06307e2001-07-03 10:35:50 +000013238 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013239 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013240
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013241 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013242 return (total);
13243 }
13244 case XPATH_OP_VALUE:
13245 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013246 xmlXPathCacheObjectCopy(ctxt->context,
13247 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013248 return (total);
13249 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000013250 xmlXPathObjectPtr val;
13251
Daniel Veillardf06307e2001-07-03 10:35:50 +000013252 if (op->ch1 != -1)
13253 total +=
13254 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013255 if (op->value5 == NULL) {
13256 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13257 if (val == NULL) {
13258 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13259 return(0);
13260 }
13261 valuePush(ctxt, val);
13262 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013263 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013264
Daniel Veillardf06307e2001-07-03 10:35:50 +000013265 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13266 if (URI == NULL) {
13267 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013268 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000013269 op->value4, op->value5);
13270 return (total);
13271 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013272 val = xmlXPathVariableLookupNS(ctxt->context,
13273 op->value4, URI);
13274 if (val == NULL) {
13275 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13276 return(0);
13277 }
13278 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013279 }
13280 return (total);
13281 }
13282 case XPATH_OP_FUNCTION:{
13283 xmlXPathFunction func;
13284 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000013285 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013286
13287 if (op->ch1 != -1)
13288 total +=
13289 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013290 if (ctxt->valueNr < op->value) {
13291 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013292 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013293 ctxt->error = XPATH_INVALID_OPERAND;
13294 return (total);
13295 }
13296 for (i = 0; i < op->value; i++)
13297 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13298 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013299 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013300 ctxt->error = XPATH_INVALID_OPERAND;
13301 return (total);
13302 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013303 if (op->cache != NULL)
William M. Brackad0e67c2004-12-01 14:35:10 +000013304 XML_CAST_FPTR(func) = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013305 else {
13306 const xmlChar *URI = NULL;
13307
13308 if (op->value5 == NULL)
13309 func =
13310 xmlXPathFunctionLookup(ctxt->context,
13311 op->value4);
13312 else {
13313 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13314 if (URI == NULL) {
13315 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013316 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000013317 op->value4, op->value5);
13318 return (total);
13319 }
13320 func = xmlXPathFunctionLookupNS(ctxt->context,
13321 op->value4, URI);
13322 }
13323 if (func == NULL) {
13324 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013325 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000013326 op->value4);
13327 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013328 }
William M. Brackad0e67c2004-12-01 14:35:10 +000013329 op->cache = XML_CAST_FPTR(func);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013330 op->cacheURI = (void *) URI;
13331 }
13332 oldFunc = ctxt->context->function;
13333 oldFuncURI = ctxt->context->functionURI;
13334 ctxt->context->function = op->value4;
13335 ctxt->context->functionURI = op->cacheURI;
13336 func(ctxt, op->value);
13337 ctxt->context->function = oldFunc;
13338 ctxt->context->functionURI = oldFuncURI;
13339 return (total);
13340 }
13341 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000013342 bakd = ctxt->context->doc;
13343 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000013344 pp = ctxt->context->proximityPosition;
13345 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013346 if (op->ch1 != -1)
13347 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
William M. Brack645a9242004-11-09 12:20:42 +000013348 ctxt->context->contextSize = cs;
13349 ctxt->context->proximityPosition = pp;
Daniel Veillard088bf112002-05-14 11:03:59 +000013350 ctxt->context->node = bak;
William M. Brack645a9242004-11-09 12:20:42 +000013351 ctxt->context->doc = bakd;
Daniel Veillard556c6682001-10-06 09:59:51 +000013352 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000013353 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013354 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000013355 ctxt->context->doc = bakd;
13356 ctxt->context->node = bak;
13357 CHECK_ERROR0;
13358 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013359 return (total);
13360 case XPATH_OP_PREDICATE:
13361 case XPATH_OP_FILTER:{
13362 xmlXPathObjectPtr res;
13363 xmlXPathObjectPtr obj, tmp;
13364 xmlNodeSetPtr newset = NULL;
13365 xmlNodeSetPtr oldset;
13366 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000013367 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013368 int i;
13369
13370 /*
13371 * Optimization for ()[1] selection i.e. the first elem
13372 */
13373 if ((op->ch1 != -1) && (op->ch2 != -1) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013374#ifdef XP_OPTIMIZED_FILTER_FIRST
13375 /*
13376 * FILTER TODO: Can we assume that the inner processing
13377 * will result in an ordered list if we have an
13378 * XPATH_OP_FILTER?
13379 * What about an additional field or flag on
13380 * xmlXPathObject like @sorted ? This way we wouln'd need
13381 * to assume anything, so it would be more robust and
13382 * easier to optimize.
13383 */
13384 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13385 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13386#else
13387 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13388#endif
13389 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013390 xmlXPathObjectPtr val;
13391
13392 val = comp->steps[op->ch2].value4;
13393 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13394 (val->floatval == 1.0)) {
13395 xmlNodePtr first = NULL;
13396
13397 total +=
13398 xmlXPathCompOpEvalFirst(ctxt,
13399 &comp->steps[op->ch1],
13400 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000013401 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013402 /*
13403 * The nodeset should be in document order,
13404 * Keep only the first value
13405 */
13406 if ((ctxt->value != NULL) &&
13407 (ctxt->value->type == XPATH_NODESET) &&
13408 (ctxt->value->nodesetval != NULL) &&
13409 (ctxt->value->nodesetval->nodeNr > 1))
13410 ctxt->value->nodesetval->nodeNr = 1;
13411 return (total);
13412 }
13413 }
13414 /*
13415 * Optimization for ()[last()] selection i.e. the last elem
13416 */
13417 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13418 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13419 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13420 int f = comp->steps[op->ch2].ch1;
13421
13422 if ((f != -1) &&
13423 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13424 (comp->steps[f].value5 == NULL) &&
13425 (comp->steps[f].value == 0) &&
13426 (comp->steps[f].value4 != NULL) &&
13427 (xmlStrEqual
13428 (comp->steps[f].value4, BAD_CAST "last"))) {
13429 xmlNodePtr last = NULL;
13430
13431 total +=
13432 xmlXPathCompOpEvalLast(ctxt,
13433 &comp->steps[op->ch1],
13434 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000013435 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013436 /*
13437 * The nodeset should be in document order,
13438 * Keep only the last value
13439 */
13440 if ((ctxt->value != NULL) &&
13441 (ctxt->value->type == XPATH_NODESET) &&
13442 (ctxt->value->nodesetval != NULL) &&
13443 (ctxt->value->nodesetval->nodeTab != NULL) &&
13444 (ctxt->value->nodesetval->nodeNr > 1)) {
13445 ctxt->value->nodesetval->nodeTab[0] =
13446 ctxt->value->nodesetval->nodeTab[ctxt->
13447 value->
13448 nodesetval->
13449 nodeNr -
13450 1];
13451 ctxt->value->nodesetval->nodeNr = 1;
13452 }
13453 return (total);
13454 }
13455 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013456 /*
13457 * Process inner predicates first.
13458 * Example "index[parent::book][1]":
13459 * ...
13460 * PREDICATE <-- we are here "[1]"
13461 * PREDICATE <-- process "[parent::book]" first
13462 * SORT
13463 * COLLECT 'parent' 'name' 'node' book
13464 * NODE
13465 * ELEM Object is a number : 1
13466 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013467 if (op->ch1 != -1)
13468 total +=
13469 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013470 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013471 if (op->ch2 == -1)
13472 return (total);
13473 if (ctxt->value == NULL)
13474 return (total);
13475
13476 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013477
13478#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013479 /*
13480 * Hum are we filtering the result of an XPointer expression
13481 */
13482 if (ctxt->value->type == XPATH_LOCATIONSET) {
13483 xmlLocationSetPtr newlocset = NULL;
13484 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013485
Daniel Veillardf06307e2001-07-03 10:35:50 +000013486 /*
13487 * Extract the old locset, and then evaluate the result of the
13488 * expression for all the element in the locset. use it to grow
13489 * up a new locset.
13490 */
13491 CHECK_TYPE0(XPATH_LOCATIONSET);
13492 obj = valuePop(ctxt);
13493 oldlocset = obj->user;
13494 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013495
Daniel Veillardf06307e2001-07-03 10:35:50 +000013496 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13497 ctxt->context->contextSize = 0;
13498 ctxt->context->proximityPosition = 0;
13499 if (op->ch2 != -1)
13500 total +=
13501 xmlXPathCompOpEval(ctxt,
13502 &comp->steps[op->ch2]);
13503 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013504 if (res != NULL) {
13505 xmlXPathReleaseObject(ctxt->context, res);
13506 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013507 valuePush(ctxt, obj);
13508 CHECK_ERROR0;
13509 return (total);
13510 }
13511 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013512
Daniel Veillardf06307e2001-07-03 10:35:50 +000013513 for (i = 0; i < oldlocset->locNr; i++) {
13514 /*
13515 * Run the evaluation with a node list made of a
13516 * single item in the nodelocset.
13517 */
13518 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013519 ctxt->context->contextSize = oldlocset->locNr;
13520 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013521 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13522 ctxt->context->node);
William M. Brackf7eb7942003-12-31 07:59:17 +000013523 valuePush(ctxt, tmp);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013524
Daniel Veillardf06307e2001-07-03 10:35:50 +000013525 if (op->ch2 != -1)
13526 total +=
13527 xmlXPathCompOpEval(ctxt,
13528 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013529 if (ctxt->error != XPATH_EXPRESSION_OK) {
13530 xmlXPathFreeObject(obj);
13531 return(0);
13532 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013533
Daniel Veillardf06307e2001-07-03 10:35:50 +000013534 /*
13535 * The result of the evaluation need to be tested to
13536 * decided whether the filter succeeded or not
13537 */
13538 res = valuePop(ctxt);
13539 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13540 xmlXPtrLocationSetAdd(newlocset,
13541 xmlXPathObjectCopy
13542 (oldlocset->locTab[i]));
13543 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013544
Daniel Veillardf06307e2001-07-03 10:35:50 +000013545 /*
13546 * Cleanup
13547 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013548 if (res != NULL) {
13549 xmlXPathReleaseObject(ctxt->context, res);
13550 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013551 if (ctxt->value == tmp) {
13552 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013553 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013554 }
13555
13556 ctxt->context->node = NULL;
13557 }
13558
13559 /*
13560 * The result is used as the new evaluation locset.
13561 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013562 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013563 ctxt->context->node = NULL;
13564 ctxt->context->contextSize = -1;
13565 ctxt->context->proximityPosition = -1;
13566 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13567 ctxt->context->node = oldnode;
13568 return (total);
13569 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013570#endif /* LIBXML_XPTR_ENABLED */
13571
Daniel Veillardf06307e2001-07-03 10:35:50 +000013572 /*
13573 * Extract the old set, and then evaluate the result of the
13574 * expression for all the element in the set. use it to grow
13575 * up a new set.
13576 */
13577 CHECK_TYPE0(XPATH_NODESET);
13578 obj = valuePop(ctxt);
13579 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000013580
Daniel Veillardf06307e2001-07-03 10:35:50 +000013581 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000013582 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013583 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013584
Daniel Veillardf06307e2001-07-03 10:35:50 +000013585 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13586 ctxt->context->contextSize = 0;
13587 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000013588/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000013589 if (op->ch2 != -1)
13590 total +=
13591 xmlXPathCompOpEval(ctxt,
13592 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013593 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013594 res = valuePop(ctxt);
13595 if (res != NULL)
13596 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000013597*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000013598 valuePush(ctxt, obj);
13599 ctxt->context->node = oldnode;
13600 CHECK_ERROR0;
13601 } else {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013602 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013603 /*
13604 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000013605 * Also set the xpath document in case things like
13606 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000013607 */
13608 newset = xmlXPathNodeSetCreate(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013609 /*
13610 * SPEC XPath 1.0:
13611 * "For each node in the node-set to be filtered, the
13612 * PredicateExpr is evaluated with that node as the
13613 * context node, with the number of nodes in the
13614 * node-set as the context size, and with the proximity
13615 * position of the node in the node-set with respect to
13616 * the axis as the context position;"
13617 * @oldset is the node-set" to be filtered.
13618 *
13619 * SPEC XPath 1.0:
13620 * "only predicates change the context position and
13621 * context size (see [2.4 Predicates])."
13622 * Example:
13623 * node-set context pos
13624 * nA 1
13625 * nB 2
13626 * nC 3
13627 * After applying predicate [position() > 1] :
13628 * node-set context pos
13629 * nB 1
13630 * nC 2
13631 *
13632 * removed the first node in the node-set, then
13633 * the context position of the
13634 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013635 for (i = 0; i < oldset->nodeNr; i++) {
13636 /*
13637 * Run the evaluation with a node list made of
13638 * a single item in the nodeset.
13639 */
13640 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000013641 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13642 (oldset->nodeTab[i]->doc != NULL))
13643 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013644 if (tmp == NULL) {
13645 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13646 ctxt->context->node);
13647 } else {
13648 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13649 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013650 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013651 valuePush(ctxt, tmp);
13652 ctxt->context->contextSize = oldset->nodeNr;
13653 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013654 /*
13655 * Evaluate the predicate against the context node.
13656 * Can/should we optimize position() predicates
13657 * here (e.g. "[1]")?
13658 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013659 if (op->ch2 != -1)
13660 total +=
13661 xmlXPathCompOpEval(ctxt,
13662 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013663 if (ctxt->error != XPATH_EXPRESSION_OK) {
13664 xmlXPathFreeNodeSet(newset);
13665 xmlXPathFreeObject(obj);
13666 return(0);
13667 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013668
Daniel Veillardf06307e2001-07-03 10:35:50 +000013669 /*
William M. Brack08171912003-12-29 02:52:11 +000013670 * The result of the evaluation needs to be tested to
13671 * decide whether the filter succeeded or not
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013672 */
13673 /*
13674 * OPTIMIZE TODO: Can we use
13675 * xmlXPathNodeSetAdd*Unique()* instead?
13676 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013677 res = valuePop(ctxt);
13678 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13679 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13680 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013681
Daniel Veillardf06307e2001-07-03 10:35:50 +000013682 /*
13683 * Cleanup
13684 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013685 if (res != NULL) {
13686 xmlXPathReleaseObject(ctxt->context, res);
13687 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013688 if (ctxt->value == tmp) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013689 valuePop(ctxt);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000013690 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013691 /*
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013692 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013693 * in order to avoid massive recreation inside this
13694 * loop.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013695 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013696 } else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013697 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013698 ctxt->context->node = NULL;
13699 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013700 if (tmp != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013701 xmlXPathReleaseObject(ctxt->context, tmp);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013702 /*
13703 * The result is used as the new evaluation set.
13704 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013705 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013706 ctxt->context->node = NULL;
13707 ctxt->context->contextSize = -1;
13708 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000013709 /* may want to move this past the '}' later */
13710 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013711 valuePush(ctxt,
13712 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013713 }
13714 ctxt->context->node = oldnode;
13715 return (total);
13716 }
13717 case XPATH_OP_SORT:
13718 if (op->ch1 != -1)
13719 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013720 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013721 if ((ctxt->value != NULL) &&
13722 (ctxt->value->type == XPATH_NODESET) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013723 (ctxt->value->nodesetval != NULL) &&
13724 (ctxt->value->nodesetval->nodeNr > 1))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013725 {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013726 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013727 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013728 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013729#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013730 case XPATH_OP_RANGETO:{
13731 xmlXPathObjectPtr range;
13732 xmlXPathObjectPtr res, obj;
13733 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000013734 xmlLocationSetPtr newlocset = NULL;
13735 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013736 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000013737 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013738
Daniel Veillardf06307e2001-07-03 10:35:50 +000013739 if (op->ch1 != -1)
13740 total +=
13741 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13742 if (op->ch2 == -1)
13743 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013744
William M. Brack08171912003-12-29 02:52:11 +000013745 if (ctxt->value->type == XPATH_LOCATIONSET) {
13746 /*
13747 * Extract the old locset, and then evaluate the result of the
13748 * expression for all the element in the locset. use it to grow
13749 * up a new locset.
13750 */
13751 CHECK_TYPE0(XPATH_LOCATIONSET);
13752 obj = valuePop(ctxt);
13753 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013754
William M. Brack08171912003-12-29 02:52:11 +000013755 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000013756 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000013757 ctxt->context->contextSize = 0;
13758 ctxt->context->proximityPosition = 0;
13759 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13760 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013761 if (res != NULL) {
13762 xmlXPathReleaseObject(ctxt->context, res);
13763 }
William M. Brack08171912003-12-29 02:52:11 +000013764 valuePush(ctxt, obj);
13765 CHECK_ERROR0;
13766 return (total);
13767 }
13768 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013769
William M. Brack08171912003-12-29 02:52:11 +000013770 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013771 /*
William M. Brack08171912003-12-29 02:52:11 +000013772 * Run the evaluation with a node list made of a
13773 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000013774 */
William M. Brackf7eb7942003-12-31 07:59:17 +000013775 ctxt->context->node = oldlocset->locTab[i]->user;
13776 ctxt->context->contextSize = oldlocset->locNr;
13777 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013778 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13779 ctxt->context->node);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013780 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013781
Daniel Veillardf06307e2001-07-03 10:35:50 +000013782 if (op->ch2 != -1)
13783 total +=
13784 xmlXPathCompOpEval(ctxt,
13785 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013786 if (ctxt->error != XPATH_EXPRESSION_OK) {
13787 xmlXPathFreeObject(obj);
13788 return(0);
13789 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013790
Daniel Veillardf06307e2001-07-03 10:35:50 +000013791 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000013792 if (res->type == XPATH_LOCATIONSET) {
13793 xmlLocationSetPtr rloc =
13794 (xmlLocationSetPtr)res->user;
13795 for (j=0; j<rloc->locNr; j++) {
13796 range = xmlXPtrNewRange(
13797 oldlocset->locTab[i]->user,
13798 oldlocset->locTab[i]->index,
13799 rloc->locTab[j]->user2,
13800 rloc->locTab[j]->index2);
13801 if (range != NULL) {
13802 xmlXPtrLocationSetAdd(newlocset, range);
13803 }
13804 }
13805 } else {
13806 range = xmlXPtrNewRangeNodeObject(
13807 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13808 if (range != NULL) {
13809 xmlXPtrLocationSetAdd(newlocset,range);
13810 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013811 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013812
Daniel Veillardf06307e2001-07-03 10:35:50 +000013813 /*
13814 * Cleanup
13815 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013816 if (res != NULL) {
13817 xmlXPathReleaseObject(ctxt->context, res);
13818 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013819 if (ctxt->value == tmp) {
13820 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013821 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013822 }
13823
13824 ctxt->context->node = NULL;
13825 }
William M. Brack72ee48d2003-12-30 08:30:19 +000013826 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000013827 CHECK_TYPE0(XPATH_NODESET);
13828 obj = valuePop(ctxt);
13829 oldset = obj->nodesetval;
13830 ctxt->context->node = NULL;
13831
13832 newlocset = xmlXPtrLocationSetCreate(NULL);
13833
13834 if (oldset != NULL) {
13835 for (i = 0; i < oldset->nodeNr; i++) {
13836 /*
13837 * Run the evaluation with a node list made of a single item
13838 * in the nodeset.
13839 */
13840 ctxt->context->node = oldset->nodeTab[i];
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013841 /*
13842 * OPTIMIZE TODO: Avoid recreation for every iteration.
13843 */
13844 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13845 ctxt->context->node);
William M. Brack08171912003-12-29 02:52:11 +000013846 valuePush(ctxt, tmp);
13847
13848 if (op->ch2 != -1)
13849 total +=
13850 xmlXPathCompOpEval(ctxt,
13851 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013852 if (ctxt->error != XPATH_EXPRESSION_OK) {
13853 xmlXPathFreeObject(obj);
13854 return(0);
13855 }
William M. Brack08171912003-12-29 02:52:11 +000013856
William M. Brack08171912003-12-29 02:52:11 +000013857 res = valuePop(ctxt);
13858 range =
13859 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13860 res);
13861 if (range != NULL) {
13862 xmlXPtrLocationSetAdd(newlocset, range);
13863 }
13864
13865 /*
13866 * Cleanup
13867 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013868 if (res != NULL) {
13869 xmlXPathReleaseObject(ctxt->context, res);
13870 }
William M. Brack08171912003-12-29 02:52:11 +000013871 if (ctxt->value == tmp) {
13872 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013873 xmlXPathReleaseObject(ctxt->context, res);
William M. Brack08171912003-12-29 02:52:11 +000013874 }
13875
13876 ctxt->context->node = NULL;
13877 }
13878 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013879 }
13880
13881 /*
13882 * The result is used as the new evaluation set.
13883 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013884 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013885 ctxt->context->node = NULL;
13886 ctxt->context->contextSize = -1;
13887 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000013888 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013889 return (total);
13890 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013891#endif /* LIBXML_XPTR_ENABLED */
13892 }
13893 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000013894 "XPath: unknown precompiled operation %d\n", op->op);
13895 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013896}
13897
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013898/**
13899 * xmlXPathCompOpEvalToBoolean:
13900 * @ctxt: the XPath parser context
13901 *
13902 * Evaluates if the expression evaluates to true.
13903 *
13904 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13905 */
13906static int
13907xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013908 xmlXPathStepOpPtr op,
13909 int isPredicate)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013910{
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013911 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013912
13913start:
13914 /* comp = ctxt->comp; */
13915 switch (op->op) {
13916 case XPATH_OP_END:
13917 return (0);
13918 case XPATH_OP_VALUE:
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013919 resObj = (xmlXPathObjectPtr) op->value4;
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000013920 if (isPredicate)
13921 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13922 return(xmlXPathCastToBoolean(resObj));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013923 case XPATH_OP_SORT:
13924 /*
13925 * We don't need sorting for boolean results. Skip this one.
13926 */
13927 if (op->ch1 != -1) {
13928 op = &ctxt->comp->steps[op->ch1];
13929 goto start;
13930 }
13931 return(0);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013932 case XPATH_OP_COLLECT:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013933 if (op->ch1 == -1)
13934 return(0);
13935
13936 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13937 if (ctxt->error != XPATH_EXPRESSION_OK)
13938 return(-1);
13939
13940 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13941 if (ctxt->error != XPATH_EXPRESSION_OK)
13942 return(-1);
13943
13944 resObj = valuePop(ctxt);
13945 if (resObj == NULL)
13946 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013947 break;
13948 default:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013949 /*
13950 * Fallback to call xmlXPathCompOpEval().
13951 */
13952 xmlXPathCompOpEval(ctxt, op);
13953 if (ctxt->error != XPATH_EXPRESSION_OK)
13954 return(-1);
13955
13956 resObj = valuePop(ctxt);
13957 if (resObj == NULL)
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000013958 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013959 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013960 }
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013961
13962 if (resObj) {
13963 int res;
13964
13965 if (resObj->type == XPATH_BOOLEAN) {
13966 res = resObj->boolval;
13967 } else if (isPredicate) {
13968 /*
13969 * For predicates a result of type "number" is handled
13970 * differently:
13971 * SPEC XPath 1.0:
13972 * "If the result is a number, the result will be converted
13973 * to true if the number is equal to the context position
13974 * and will be converted to false otherwise;"
13975 */
13976 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
13977 } else {
13978 res = xmlXPathCastToBoolean(resObj);
13979 }
13980 xmlXPathReleaseObject(ctxt->context, resObj);
13981 return(res);
13982 }
13983
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013984 return(0);
13985}
13986
Daniel Veillard56de87e2005-02-16 00:22:29 +000013987#ifdef XPATH_STREAMING
13988/**
13989 * xmlXPathRunStreamEval:
13990 * @ctxt: the XPath parser context with the compiled expression
13991 *
13992 * Evaluate the Precompiled Streamable XPath expression in the given context.
13993 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013994static int
13995xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
13996 xmlXPathObjectPtr *resultSeq, int toBool)
13997{
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013998 int max_depth, min_depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013999 int from_root;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014000 int ret, depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014001 int eval_all_nodes;
William M. Brack12d37ab2005-02-21 13:54:07 +000014002 xmlNodePtr cur = NULL, limit = NULL;
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014003 xmlStreamCtxtPtr patstream = NULL;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014004
14005 int nb_nodes = 0;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014006
14007 if ((ctxt == NULL) || (comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014008 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014009 max_depth = xmlPatternMaxDepth(comp);
14010 if (max_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014011 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014012 if (max_depth == -2)
14013 max_depth = 10000;
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014014 min_depth = xmlPatternMinDepth(comp);
14015 if (min_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014016 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014017 from_root = xmlPatternFromRoot(comp);
14018 if (from_root < 0)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014019 return(-1);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014020#if 0
14021 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14022#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000014023
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014024 if (! toBool) {
14025 if (resultSeq == NULL)
14026 return(-1);
14027 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14028 if (*resultSeq == NULL)
14029 return(-1);
14030 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014031
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014032 /*
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014033 * handle the special cases of "/" amd "." being matched
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014034 */
14035 if (min_depth == 0) {
14036 if (from_root) {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014037 /* Select "/" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014038 if (toBool)
14039 return(1);
14040 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14041 (xmlNodePtr) ctxt->doc);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014042 } else {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014043 /* Select "self::node()" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014044 if (toBool)
14045 return(1);
14046 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014047 }
14048 }
14049 if (max_depth == 0) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014050 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014051 }
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014052
Daniel Veillard56de87e2005-02-16 00:22:29 +000014053 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000014054 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014055 } else if (ctxt->node != NULL) {
14056 switch (ctxt->node->type) {
14057 case XML_ELEMENT_NODE:
14058 case XML_DOCUMENT_NODE:
14059 case XML_DOCUMENT_FRAG_NODE:
14060 case XML_HTML_DOCUMENT_NODE:
14061#ifdef LIBXML_DOCB_ENABLED
14062 case XML_DOCB_DOCUMENT_NODE:
14063#endif
14064 cur = ctxt->node;
14065 break;
14066 case XML_ATTRIBUTE_NODE:
14067 case XML_TEXT_NODE:
14068 case XML_CDATA_SECTION_NODE:
14069 case XML_ENTITY_REF_NODE:
14070 case XML_ENTITY_NODE:
14071 case XML_PI_NODE:
14072 case XML_COMMENT_NODE:
14073 case XML_NOTATION_NODE:
14074 case XML_DTD_NODE:
14075 case XML_DOCUMENT_TYPE_NODE:
14076 case XML_ELEMENT_DECL:
14077 case XML_ATTRIBUTE_DECL:
14078 case XML_ENTITY_DECL:
14079 case XML_NAMESPACE_DECL:
14080 case XML_XINCLUDE_START:
14081 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000014082 break;
14083 }
14084 limit = cur;
14085 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014086 if (cur == NULL) {
14087 return(0);
14088 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014089
14090 patstream = xmlPatternGetStreamCtxt(comp);
14091 if (patstream == NULL) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014092 /*
14093 * QUESTION TODO: Is this an error?
14094 */
14095 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014096 }
14097
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014098 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014099
Daniel Veillard56de87e2005-02-16 00:22:29 +000014100 if (from_root) {
14101 ret = xmlStreamPush(patstream, NULL, NULL);
14102 if (ret < 0) {
14103 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014104 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014105 goto return_1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014106 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014107 }
14108 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014109 depth = 0;
14110 goto scan_children;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014111next_node:
Daniel Veillardd3ff7ef2006-02-27 19:43:17 +000014112 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014113 nb_nodes++;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014114
14115 switch (cur->type) {
14116 case XML_ELEMENT_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014117 case XML_TEXT_NODE:
14118 case XML_CDATA_SECTION_NODE:
14119 case XML_COMMENT_NODE:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014120 case XML_PI_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014121 if (cur->type == XML_ELEMENT_NODE) {
14122 ret = xmlStreamPush(patstream, cur->name,
Daniel Veillard56de87e2005-02-16 00:22:29 +000014123 (cur->ns ? cur->ns->href : NULL));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014124 } else if (eval_all_nodes)
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014125 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14126 else
14127 break;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014128
14129 if (ret < 0) {
14130 /* NOP. */
14131 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014132 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014133 goto return_1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014134 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014135 }
14136 if ((cur->children == NULL) || (depth >= max_depth)) {
14137 ret = xmlStreamPop(patstream);
14138 while (cur->next != NULL) {
14139 cur = cur->next;
14140 if ((cur->type != XML_ENTITY_DECL) &&
14141 (cur->type != XML_DTD_NODE))
14142 goto next_node;
14143 }
14144 }
14145 default:
14146 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014147 }
14148
Daniel Veillard56de87e2005-02-16 00:22:29 +000014149scan_children:
14150 if ((cur->children != NULL) && (depth < max_depth)) {
14151 /*
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014152 * Do not descend on entities declarations
Daniel Veillard56de87e2005-02-16 00:22:29 +000014153 */
14154 if (cur->children->type != XML_ENTITY_DECL) {
14155 cur = cur->children;
14156 depth++;
14157 /*
14158 * Skip DTDs
14159 */
14160 if (cur->type != XML_DTD_NODE)
14161 continue;
14162 }
14163 }
14164
14165 if (cur == limit)
14166 break;
14167
14168 while (cur->next != NULL) {
14169 cur = cur->next;
14170 if ((cur->type != XML_ENTITY_DECL) &&
14171 (cur->type != XML_DTD_NODE))
14172 goto next_node;
14173 }
14174
14175 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014176 cur = cur->parent;
14177 depth--;
14178 if ((cur == NULL) || (cur == limit))
14179 goto done;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014180 if (cur->type == XML_ELEMENT_NODE) {
14181 ret = xmlStreamPop(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014182 } else if ((eval_all_nodes) &&
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014183 ((cur->type == XML_TEXT_NODE) ||
14184 (cur->type == XML_CDATA_SECTION_NODE) ||
14185 (cur->type == XML_COMMENT_NODE) ||
14186 (cur->type == XML_PI_NODE)))
14187 {
14188 ret = xmlStreamPop(patstream);
14189 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014190 if (cur->next != NULL) {
14191 cur = cur->next;
14192 break;
14193 }
14194 } while (cur != NULL);
14195
14196 } while ((cur != NULL) && (depth >= 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014197
Daniel Veillard56de87e2005-02-16 00:22:29 +000014198done:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014199
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014200#if 0
14201 printf("stream eval: checked %d nodes selected %d\n",
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014202 nb_nodes, retObj->nodesetval->nodeNr);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014203#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014204
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014205 if (patstream)
14206 xmlFreeStreamCtxt(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014207 return(0);
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014208
14209return_1:
14210 if (patstream)
14211 xmlFreeStreamCtxt(patstream);
14212 return(1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014213}
14214#endif /* XPATH_STREAMING */
14215
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014216/**
14217 * xmlXPathRunEval:
14218 * @ctxt: the XPath parser context with the compiled expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014219 * @toBool: evaluate to a boolean result
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014220 *
14221 * Evaluate the Precompiled XPath expression in the given context.
14222 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014223static int
14224xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14225{
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014226 xmlXPathCompExprPtr comp;
14227
14228 if ((ctxt == NULL) || (ctxt->comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014229 return(-1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014230
14231 if (ctxt->valueTab == NULL) {
14232 /* Allocate the value stack */
14233 ctxt->valueTab = (xmlXPathObjectPtr *)
14234 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14235 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000014236 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014237 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014238 }
14239 ctxt->valueNr = 0;
14240 ctxt->valueMax = 10;
14241 ctxt->value = NULL;
14242 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014243#ifdef XPATH_STREAMING
14244 if (ctxt->comp->stream) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014245 int res;
14246
14247 if (toBool) {
14248 /*
14249 * Evaluation to boolean result.
14250 */
14251 res = xmlXPathRunStreamEval(ctxt->context,
14252 ctxt->comp->stream, NULL, 1);
14253 if (res != -1)
14254 return(res);
14255 } else {
14256 xmlXPathObjectPtr resObj = NULL;
14257
14258 /*
14259 * Evaluation to a sequence.
14260 */
14261 res = xmlXPathRunStreamEval(ctxt->context,
14262 ctxt->comp->stream, &resObj, 0);
14263
14264 if ((res != -1) && (resObj != NULL)) {
14265 valuePush(ctxt, resObj);
14266 return(0);
14267 }
14268 if (resObj != NULL)
14269 xmlXPathReleaseObject(ctxt->context, resObj);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014270 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014271 /*
14272 * QUESTION TODO: This falls back to normal XPath evaluation
14273 * if res == -1. Is this intended?
14274 */
Daniel Veillard56de87e2005-02-16 00:22:29 +000014275 }
14276#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014277 comp = ctxt->comp;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014278 if (comp->last < 0) {
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014279 xmlGenericError(xmlGenericErrorContext,
14280 "xmlXPathRunEval: last is less than zero\n");
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014281 return(-1);
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014282 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014283 if (toBool)
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014284 return(xmlXPathCompOpEvalToBoolean(ctxt,
14285 &comp->steps[comp->last], 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014286 else
14287 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14288
14289 return(0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014290}
14291
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014292/************************************************************************
14293 * *
14294 * Public interfaces *
14295 * *
14296 ************************************************************************/
14297
14298/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014299 * xmlXPathEvalPredicate:
14300 * @ctxt: the XPath context
14301 * @res: the Predicate Expression evaluation result
14302 *
14303 * Evaluate a predicate result for the current node.
14304 * A PredicateExpr is evaluated by evaluating the Expr and converting
14305 * the result to a boolean. If the result is a number, the result will
14306 * be converted to true if the number is equal to the position of the
14307 * context node in the context node list (as returned by the position
14308 * function) and will be converted to false otherwise; if the result
14309 * is not a number, then the result will be converted as if by a call
14310 * to the boolean function.
14311 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014312 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014313 */
14314int
14315xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014316 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014317 switch (res->type) {
14318 case XPATH_BOOLEAN:
14319 return(res->boolval);
14320 case XPATH_NUMBER:
14321 return(res->floatval == ctxt->proximityPosition);
14322 case XPATH_NODESET:
14323 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000014324 if (res->nodesetval == NULL)
14325 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014326 return(res->nodesetval->nodeNr != 0);
14327 case XPATH_STRING:
14328 return((res->stringval != NULL) &&
14329 (xmlStrlen(res->stringval) != 0));
14330 default:
14331 STRANGE
14332 }
14333 return(0);
14334}
14335
14336/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014337 * xmlXPathEvaluatePredicateResult:
14338 * @ctxt: the XPath Parser context
14339 * @res: the Predicate Expression evaluation result
14340 *
14341 * Evaluate a predicate result for the current node.
14342 * A PredicateExpr is evaluated by evaluating the Expr and converting
14343 * the result to a boolean. If the result is a number, the result will
14344 * be converted to true if the number is equal to the position of the
14345 * context node in the context node list (as returned by the position
14346 * function) and will be converted to false otherwise; if the result
14347 * is not a number, then the result will be converted as if by a call
14348 * to the boolean function.
14349 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014350 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014351 */
14352int
14353xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14354 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014355 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014356 switch (res->type) {
14357 case XPATH_BOOLEAN:
14358 return(res->boolval);
14359 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000014360#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000014361 return((res->floatval == ctxt->context->proximityPosition) &&
14362 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000014363#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014364 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000014365#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014366 case XPATH_NODESET:
14367 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000014368 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000014369 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014370 return(res->nodesetval->nodeNr != 0);
14371 case XPATH_STRING:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014372 return((res->stringval != NULL) && (res->stringval[0] != 0));
William M. Brack08171912003-12-29 02:52:11 +000014373#ifdef LIBXML_XPTR_ENABLED
14374 case XPATH_LOCATIONSET:{
14375 xmlLocationSetPtr ptr = res->user;
14376 if (ptr == NULL)
14377 return(0);
14378 return (ptr->locNr != 0);
14379 }
14380#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014381 default:
14382 STRANGE
14383 }
14384 return(0);
14385}
14386
Daniel Veillard56de87e2005-02-16 00:22:29 +000014387#ifdef XPATH_STREAMING
14388/**
14389 * xmlXPathTryStreamCompile:
14390 * @ctxt: an XPath context
14391 * @str: the XPath expression
14392 *
14393 * Try to compile the XPath expression as a streamable subset.
14394 *
14395 * Returns the compiled expression or NULL if failed to compile.
14396 */
14397static xmlXPathCompExprPtr
14398xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14399 /*
14400 * Optimization: use streaming patterns when the XPath expression can
14401 * be compiled to a stream lookup
14402 */
14403 xmlPatternPtr stream;
14404 xmlXPathCompExprPtr comp;
14405 xmlDictPtr dict = NULL;
14406 const xmlChar **namespaces = NULL;
14407 xmlNsPtr ns;
14408 int i, j;
14409
14410 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14411 (!xmlStrchr(str, '@'))) {
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014412 const xmlChar *tmp;
14413
14414 /*
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014415 * We don't try to handle expressions using the verbose axis
14416 * specifiers ("::"), just the simplied form at this point.
14417 * Additionally, if there is no list of namespaces available and
14418 * there's a ":" in the expression, indicating a prefixed QName,
14419 * then we won't try to compile either. xmlPatterncompile() needs
14420 * to have a list of namespaces at compilation time in order to
14421 * compile prefixed name tests.
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014422 */
14423 tmp = xmlStrchr(str, ':');
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014424 if ((tmp != NULL) &&
14425 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14426 return(NULL);
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014427
Daniel Veillard56de87e2005-02-16 00:22:29 +000014428 if (ctxt != NULL) {
14429 dict = ctxt->dict;
14430 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000014431 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000014432 if (namespaces == NULL) {
14433 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14434 return(NULL);
14435 }
14436 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14437 ns = ctxt->namespaces[j];
14438 namespaces[i++] = ns->href;
14439 namespaces[i++] = ns->prefix;
14440 }
14441 namespaces[i++] = NULL;
14442 namespaces[i++] = NULL;
14443 }
14444 }
14445
William M. Brackea152c02005-06-09 18:12:28 +000014446 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14447 &namespaces[0]);
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014448 if (namespaces != NULL) {
14449 xmlFree((xmlChar **)namespaces);
14450 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014451 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14452 comp = xmlXPathNewCompExpr();
14453 if (comp == NULL) {
14454 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14455 return(NULL);
14456 }
14457 comp->stream = stream;
14458 comp->dict = dict;
14459 if (comp->dict)
14460 xmlDictReference(comp->dict);
14461 return(comp);
14462 }
14463 xmlFreePattern(stream);
14464 }
14465 return(NULL);
14466}
14467#endif /* XPATH_STREAMING */
14468
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014469static int
14470xmlXPathCanRewriteDosExpression(xmlChar *expr)
14471{
14472 if (expr == NULL)
14473 return(0);
14474 do {
14475 if ((*expr == '/') && (*(++expr) == '/'))
14476 return(1);
14477 } while (*expr++);
14478 return(0);
14479}
14480static void
14481xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14482{
14483 /*
14484 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14485 * internal representation.
14486 */
14487 if (op->ch1 != -1) {
14488 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14489 ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
14490 ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
14491 ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
14492 {
14493 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014494 * This is a "child::foo"
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014495 */
14496 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14497
14498 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14499 (prevop->ch1 != -1) &&
14500 ((xmlXPathAxisVal) prevop->value ==
14501 AXIS_DESCENDANT_OR_SELF) &&
14502 (prevop->ch2 == -1) &&
14503 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014504 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
14505 (comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014506 {
14507 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014508 * This is a "/descendant-or-self::node()" without predicates.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014509 * Eliminate it.
14510 */
14511 op->ch1 = prevop->ch1;
14512 op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
14513 }
14514 }
14515 if (op->ch1 != -1)
14516 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
14517 }
14518 if (op->ch2 != -1)
14519 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
14520}
14521
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014522/**
Daniel Veillard4773df22004-01-23 13:15:13 +000014523 * xmlXPathCtxtCompile:
14524 * @ctxt: an XPath context
14525 * @str: the XPath expression
14526 *
14527 * Compile an XPath expression
14528 *
14529 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14530 * the caller has to free the object.
14531 */
14532xmlXPathCompExprPtr
14533xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14534 xmlXPathParserContextPtr pctxt;
14535 xmlXPathCompExprPtr comp;
14536
Daniel Veillard56de87e2005-02-16 00:22:29 +000014537#ifdef XPATH_STREAMING
14538 comp = xmlXPathTryStreamCompile(ctxt, str);
14539 if (comp != NULL)
14540 return(comp);
14541#endif
14542
Daniel Veillard4773df22004-01-23 13:15:13 +000014543 xmlXPathInit();
14544
14545 pctxt = xmlXPathNewParserContext(str, ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014546 xmlXPathCompileExpr(pctxt, 1);
Daniel Veillard4773df22004-01-23 13:15:13 +000014547
14548 if( pctxt->error != XPATH_EXPRESSION_OK )
14549 {
14550 xmlXPathFreeParserContext(pctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000014551 return(NULL);
Daniel Veillard4773df22004-01-23 13:15:13 +000014552 }
14553
14554 if (*pctxt->cur != 0) {
14555 /*
14556 * aleksey: in some cases this line prints *second* error message
14557 * (see bug #78858) and probably this should be fixed.
14558 * However, we are not sure that all error messages are printed
14559 * out in other places. It's not critical so we leave it as-is for now
14560 */
14561 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14562 comp = NULL;
14563 } else {
14564 comp = pctxt->comp;
14565 pctxt->comp = NULL;
14566 }
14567 xmlXPathFreeParserContext(pctxt);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014568
Daniel Veillard4773df22004-01-23 13:15:13 +000014569 if (comp != NULL) {
14570 comp->expr = xmlStrdup(str);
14571#ifdef DEBUG_EVAL_COUNTS
14572 comp->string = xmlStrdup(str);
14573 comp->nb = 0;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014574#endif
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014575 if ((comp->expr != NULL) &&
14576 (comp->nbStep > 2) &&
14577 (comp->last >= 0) &&
Kasimier T. Buchcik7cb3fa92006-06-06 15:27:46 +000014578 (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
14579 {
14580 xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014581 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014582 }
Daniel Veillard4773df22004-01-23 13:15:13 +000014583 return(comp);
14584}
14585
14586/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014587 * xmlXPathCompile:
14588 * @str: the XPath expression
14589 *
14590 * Compile an XPath expression
14591 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000014592 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014593 * the caller has to free the object.
14594 */
14595xmlXPathCompExprPtr
14596xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000014597 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014598}
14599
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014600/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014601 * xmlXPathCompiledEvalInternal:
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014602 * @comp: the compiled XPath expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014603 * @ctxt: the XPath context
14604 * @resObj: the resulting XPath object or NULL
14605 * @toBool: 1 if only a boolean result is requested
Owen Taylor3473f882001-02-23 17:55:21 +000014606 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014607 * Evaluate the Precompiled XPath expression in the given context.
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014608 * The caller has to free @resObj.
Owen Taylor3473f882001-02-23 17:55:21 +000014609 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014610 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000014611 * the caller has to free the object.
14612 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014613static int
14614xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14615 xmlXPathContextPtr ctxt,
14616 xmlXPathObjectPtr *resObj,
14617 int toBool)
14618{
14619 xmlXPathParserContextPtr pctxt;
Daniel Veillard81463942001-10-16 12:34:39 +000014620#ifndef LIBXML_THREAD_ENABLED
14621 static int reentance = 0;
14622#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014623 int res;
Owen Taylor3473f882001-02-23 17:55:21 +000014624
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014625 CHECK_CTXT_NEG(ctxt)
William M. Brackf13f77f2004-11-12 16:03:48 +000014626
14627 if (comp == NULL)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014628 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +000014629 xmlXPathInit();
14630
Daniel Veillard81463942001-10-16 12:34:39 +000014631#ifndef LIBXML_THREAD_ENABLED
14632 reentance++;
14633 if (reentance > 1)
14634 xmlXPathDisableOptimizer = 1;
14635#endif
14636
Daniel Veillardf06307e2001-07-03 10:35:50 +000014637#ifdef DEBUG_EVAL_COUNTS
14638 comp->nb++;
14639 if ((comp->string != NULL) && (comp->nb > 100)) {
14640 fprintf(stderr, "100 x %s\n", comp->string);
14641 comp->nb = 0;
14642 }
14643#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014644 pctxt = xmlXPathCompParserContext(comp, ctxt);
14645 res = xmlXPathRunEval(pctxt, toBool);
Owen Taylor3473f882001-02-23 17:55:21 +000014646
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014647 if (resObj) {
14648 if (pctxt->value == NULL) {
14649 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014650 "xmlXPathCompiledEval: evaluation failed\n");
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014651 *resObj = NULL;
14652 } else {
14653 *resObj = valuePop(pctxt);
14654 }
Owen Taylor3473f882001-02-23 17:55:21 +000014655 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014656
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014657 /*
14658 * Pop all remaining objects from the stack.
14659 */
14660 if (pctxt->valueNr > 0) {
14661 xmlXPathObjectPtr tmp;
14662 int stack = 0;
14663
14664 do {
14665 tmp = valuePop(pctxt);
14666 if (tmp != NULL) {
14667 if (tmp != NULL)
14668 stack++;
14669 xmlXPathReleaseObject(ctxt, tmp);
14670 }
14671 } while (tmp != NULL);
14672 if ((stack != 0) &&
14673 ((toBool) || ((resObj) && (*resObj))))
14674 {
14675 xmlGenericError(xmlGenericErrorContext,
14676 "xmlXPathCompiledEval: %d objects left on the stack.\n",
14677 stack);
14678 }
Owen Taylor3473f882001-02-23 17:55:21 +000014679 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014680
14681 if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14682 xmlXPathFreeObject(*resObj);
14683 *resObj = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014684 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014685 pctxt->comp = NULL;
14686 xmlXPathFreeParserContext(pctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000014687#ifndef LIBXML_THREAD_ENABLED
14688 reentance--;
14689#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014690
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014691 return(res);
14692}
14693
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014694/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014695 * xmlXPathCompiledEval:
14696 * @comp: the compiled XPath expression
14697 * @ctx: the XPath context
14698 *
14699 * Evaluate the Precompiled XPath expression in the given context.
14700 *
14701 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14702 * the caller has to free the object.
14703 */
14704xmlXPathObjectPtr
14705xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14706{
14707 xmlXPathObjectPtr res = NULL;
14708
14709 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14710 return(res);
14711}
14712
14713/**
14714 * xmlXPathCompiledEvalToBoolean:
14715 * @comp: the compiled XPath expression
14716 * @ctxt: the XPath context
14717 *
14718 * Applies the XPath boolean() function on the result of the given
14719 * compiled expression.
14720 *
14721 * Returns 1 if the expression evaluated to true, 0 if to false and
14722 * -1 in API and internal errors.
14723 */
14724int
14725xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14726 xmlXPathContextPtr ctxt)
14727{
14728 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14729}
14730
14731/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014732 * xmlXPathEvalExpr:
14733 * @ctxt: the XPath Parser context
14734 *
14735 * Parse and evaluate an XPath expression in the given context,
14736 * then push the result on the context stack
14737 */
14738void
14739xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014740#ifdef XPATH_STREAMING
14741 xmlXPathCompExprPtr comp;
14742#endif
14743
Daniel Veillarda82b1822004-11-08 16:24:57 +000014744 if (ctxt == NULL) return;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014745
14746#ifdef XPATH_STREAMING
14747 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14748 if (comp != NULL) {
14749 if (ctxt->comp != NULL)
14750 xmlXPathFreeCompExpr(ctxt->comp);
14751 ctxt->comp = comp;
14752 if (ctxt->cur != NULL)
14753 while (*ctxt->cur != 0) ctxt->cur++;
14754 } else
14755#endif
14756 {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014757 xmlXPathCompileExpr(ctxt, 1);
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014758 /*
14759 * In this scenario the expression string will sit in ctxt->base.
14760 */
14761 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
14762 (ctxt->comp != NULL) &&
14763 (ctxt->base != NULL) &&
Kasimier T. Buchcik7cb3fa92006-06-06 15:27:46 +000014764 (ctxt->comp->nbStep > 2) &&
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014765 (ctxt->comp->last >= 0) &&
14766 (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014767 {
14768 xmlXPathRewriteDOSExpression(ctxt->comp,
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014769 &ctxt->comp->steps[ctxt->comp->last]);
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014770 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014771 }
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000014772 CHECK_ERROR;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014773 xmlXPathRunEval(ctxt, 0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014774}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014775
14776/**
14777 * xmlXPathEval:
14778 * @str: the XPath expression
14779 * @ctx: the XPath context
14780 *
14781 * Evaluate the XPath Location Path in the given context.
14782 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014783 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014784 * the caller has to free the object.
14785 */
14786xmlXPathObjectPtr
14787xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14788 xmlXPathParserContextPtr ctxt;
14789 xmlXPathObjectPtr res, tmp, init = NULL;
14790 int stack = 0;
14791
William M. Brackf13f77f2004-11-12 16:03:48 +000014792 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014793
William M. Brackf13f77f2004-11-12 16:03:48 +000014794 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014795
14796 ctxt = xmlXPathNewParserContext(str, ctx);
14797 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014798
14799 if (ctxt->value == NULL) {
14800 xmlGenericError(xmlGenericErrorContext,
14801 "xmlXPathEval: evaluation failed\n");
14802 res = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014803 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
14804#ifdef XPATH_STREAMING
14805 && (ctxt->comp->stream == NULL)
14806#endif
14807 ) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014808 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14809 res = NULL;
14810 } else {
14811 res = valuePop(ctxt);
14812 }
14813
14814 do {
14815 tmp = valuePop(ctxt);
14816 if (tmp != NULL) {
14817 if (tmp != init)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014818 stack++;
14819 xmlXPathReleaseObject(ctx, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014820 }
14821 } while (tmp != NULL);
14822 if ((stack != 0) && (res != NULL)) {
14823 xmlGenericError(xmlGenericErrorContext,
14824 "xmlXPathEval: %d object left on the stack\n",
14825 stack);
14826 }
14827 if (ctxt->error != XPATH_EXPRESSION_OK) {
14828 xmlXPathFreeObject(res);
14829 res = NULL;
14830 }
14831
Owen Taylor3473f882001-02-23 17:55:21 +000014832 xmlXPathFreeParserContext(ctxt);
14833 return(res);
14834}
14835
14836/**
14837 * xmlXPathEvalExpression:
14838 * @str: the XPath expression
14839 * @ctxt: the XPath context
14840 *
14841 * Evaluate the XPath expression in the given context.
14842 *
14843 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14844 * the caller has to free the object.
14845 */
14846xmlXPathObjectPtr
14847xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14848 xmlXPathParserContextPtr pctxt;
14849 xmlXPathObjectPtr res, tmp;
14850 int stack = 0;
14851
William M. Brackf13f77f2004-11-12 16:03:48 +000014852 CHECK_CTXT(ctxt)
Owen Taylor3473f882001-02-23 17:55:21 +000014853
William M. Brackf13f77f2004-11-12 16:03:48 +000014854 xmlXPathInit();
Owen Taylor3473f882001-02-23 17:55:21 +000014855
14856 pctxt = xmlXPathNewParserContext(str, ctxt);
14857 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000014858
14859 if (*pctxt->cur != 0) {
14860 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14861 res = NULL;
14862 } else {
14863 res = valuePop(pctxt);
14864 }
14865 do {
14866 tmp = valuePop(pctxt);
14867 if (tmp != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014868 xmlXPathReleaseObject(ctxt, tmp);
Owen Taylor3473f882001-02-23 17:55:21 +000014869 stack++;
14870 }
14871 } while (tmp != NULL);
14872 if ((stack != 0) && (res != NULL)) {
14873 xmlGenericError(xmlGenericErrorContext,
14874 "xmlXPathEvalExpression: %d object left on the stack\n",
14875 stack);
14876 }
14877 xmlXPathFreeParserContext(pctxt);
14878 return(res);
14879}
14880
Daniel Veillard42766c02002-08-22 20:52:17 +000014881/************************************************************************
14882 * *
14883 * Extra functions not pertaining to the XPath spec *
14884 * *
14885 ************************************************************************/
14886/**
14887 * xmlXPathEscapeUriFunction:
14888 * @ctxt: the XPath Parser context
14889 * @nargs: the number of arguments
14890 *
14891 * Implement the escape-uri() XPath function
14892 * string escape-uri(string $str, bool $escape-reserved)
14893 *
14894 * This function applies the URI escaping rules defined in section 2 of [RFC
14895 * 2396] to the string supplied as $uri-part, which typically represents all
14896 * or part of a URI. The effect of the function is to replace any special
14897 * character in the string by an escape sequence of the form %xx%yy...,
14898 * where xxyy... is the hexadecimal representation of the octets used to
14899 * represent the character in UTF-8.
14900 *
14901 * The set of characters that are escaped depends on the setting of the
14902 * boolean argument $escape-reserved.
14903 *
14904 * If $escape-reserved is true, all characters are escaped other than lower
14905 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14906 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14907 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14908 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14909 * A-F).
14910 *
14911 * If $escape-reserved is false, the behavior differs in that characters
14912 * referred to in [RFC 2396] as reserved characters are not escaped. These
14913 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14914 *
14915 * [RFC 2396] does not define whether escaped URIs should use lower case or
14916 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14917 * compared using string comparison functions, this function must always use
14918 * the upper-case letters A-F.
14919 *
14920 * Generally, $escape-reserved should be set to true when escaping a string
14921 * that is to form a single part of a URI, and to false when escaping an
14922 * entire URI or URI reference.
14923 *
14924 * In the case of non-ascii characters, the string is encoded according to
14925 * utf-8 and then converted according to RFC 2396.
14926 *
14927 * Examples
14928 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14929 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14930 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14931 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14932 *
14933 */
Daniel Veillard118aed72002-09-24 14:13:13 +000014934static void
Daniel Veillard42766c02002-08-22 20:52:17 +000014935xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14936 xmlXPathObjectPtr str;
14937 int escape_reserved;
14938 xmlBufferPtr target;
14939 xmlChar *cptr;
14940 xmlChar escape[4];
14941
14942 CHECK_ARITY(2);
14943
14944 escape_reserved = xmlXPathPopBoolean(ctxt);
14945
14946 CAST_TO_STRING;
14947 str = valuePop(ctxt);
14948
14949 target = xmlBufferCreate();
14950
14951 escape[0] = '%';
14952 escape[3] = 0;
14953
14954 if (target) {
14955 for (cptr = str->stringval; *cptr; cptr++) {
14956 if ((*cptr >= 'A' && *cptr <= 'Z') ||
14957 (*cptr >= 'a' && *cptr <= 'z') ||
14958 (*cptr >= '0' && *cptr <= '9') ||
14959 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
14960 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
14961 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14962 (*cptr == '%' &&
14963 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14964 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14965 (cptr[1] >= '0' && cptr[1] <= '9')) &&
14966 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14967 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14968 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14969 (!escape_reserved &&
14970 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14971 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14972 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14973 *cptr == ','))) {
14974 xmlBufferAdd(target, cptr, 1);
14975 } else {
14976 if ((*cptr >> 4) < 10)
14977 escape[1] = '0' + (*cptr >> 4);
14978 else
14979 escape[1] = 'A' - 10 + (*cptr >> 4);
14980 if ((*cptr & 0xF) < 10)
14981 escape[2] = '0' + (*cptr & 0xF);
14982 else
14983 escape[2] = 'A' - 10 + (*cptr & 0xF);
14984
14985 xmlBufferAdd(target, &escape[0], 3);
14986 }
14987 }
14988 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014989 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
14990 xmlBufferContent(target)));
Daniel Veillard42766c02002-08-22 20:52:17 +000014991 xmlBufferFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014992 xmlXPathReleaseObject(ctxt->context, str);
Daniel Veillard42766c02002-08-22 20:52:17 +000014993}
14994
Owen Taylor3473f882001-02-23 17:55:21 +000014995/**
14996 * xmlXPathRegisterAllFunctions:
14997 * @ctxt: the XPath context
14998 *
14999 * Registers all default XPath functions in this context
15000 */
15001void
15002xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15003{
15004 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15005 xmlXPathBooleanFunction);
15006 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15007 xmlXPathCeilingFunction);
15008 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15009 xmlXPathCountFunction);
15010 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15011 xmlXPathConcatFunction);
15012 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15013 xmlXPathContainsFunction);
15014 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15015 xmlXPathIdFunction);
15016 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15017 xmlXPathFalseFunction);
15018 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15019 xmlXPathFloorFunction);
15020 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15021 xmlXPathLastFunction);
15022 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15023 xmlXPathLangFunction);
15024 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15025 xmlXPathLocalNameFunction);
15026 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15027 xmlXPathNotFunction);
15028 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15029 xmlXPathNameFunction);
15030 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15031 xmlXPathNamespaceURIFunction);
15032 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15033 xmlXPathNormalizeFunction);
15034 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15035 xmlXPathNumberFunction);
15036 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15037 xmlXPathPositionFunction);
15038 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15039 xmlXPathRoundFunction);
15040 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15041 xmlXPathStringFunction);
15042 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15043 xmlXPathStringLengthFunction);
15044 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15045 xmlXPathStartsWithFunction);
15046 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15047 xmlXPathSubstringFunction);
15048 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15049 xmlXPathSubstringBeforeFunction);
15050 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15051 xmlXPathSubstringAfterFunction);
15052 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15053 xmlXPathSumFunction);
15054 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15055 xmlXPathTrueFunction);
15056 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15057 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000015058
15059 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15060 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15061 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000015062}
15063
15064#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000015065#define bottom_xpath
15066#include "elfgcchack.h"