blob: 4f0547751771ef2d0d21ae423352429d08400348 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005 *f
Owen Taylor3473f882001-02-23 17:55:21 +00006 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011 * See Copyright for the status of this software
Owen Taylor3473f882001-02-23 17:55:21 +000012 *
Daniel Veillardc5d64342001-06-24 12:13:24 +000013 * Author: daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000014 *
Owen Taylor3473f882001-02-23 17:55:21 +000015 */
16
Daniel Veillard34ce8be2002-03-18 19:37:11 +000017#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000018#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000019
Owen Taylor3473f882001-02-23 17:55:21 +000020#include <string.h>
21
22#ifdef HAVE_SYS_TYPES_H
23#include <sys/types.h>
24#endif
25#ifdef HAVE_MATH_H
26#include <math.h>
27#endif
28#ifdef HAVE_FLOAT_H
29#include <float.h>
30#endif
Owen Taylor3473f882001-02-23 17:55:21 +000031#ifdef HAVE_CTYPE_H
32#include <ctype.h>
33#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000034#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000035#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000036#endif
Owen Taylor3473f882001-02-23 17:55:21 +000037
38#include <libxml/xmlmemory.h>
39#include <libxml/tree.h>
40#include <libxml/valid.h>
41#include <libxml/xpath.h>
42#include <libxml/xpathInternals.h>
43#include <libxml/parserInternals.h>
44#include <libxml/hash.h>
45#ifdef LIBXML_XPTR_ENABLED
46#include <libxml/xpointer.h>
47#endif
48#ifdef LIBXML_DEBUG_ENABLED
49#include <libxml/debugXML.h>
50#endif
51#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000052#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000053#include <libxml/globals.h>
Daniel Veillard56de87e2005-02-16 00:22:29 +000054#ifdef LIBXML_PATTERN_ENABLED
55#include <libxml/pattern.h>
56#endif
57
58#ifdef LIBXML_PATTERN_ENABLED
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000059#define XPATH_STREAMING
Daniel Veillard56de87e2005-02-16 00:22:29 +000060#endif
Owen Taylor3473f882001-02-23 17:55:21 +000061
Daniel Veillardd96f6d32003-10-07 21:25:12 +000062#define TODO \
63 xmlGenericError(xmlGenericErrorContext, \
64 "Unimplemented block at %s:%d\n", \
65 __FILE__, __LINE__);
66
William M. Brackd1757ab2004-10-02 22:07:48 +000067/*
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000068* XP_OPTIMIZED_NON_ELEM_COMPARISON:
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +000069* If defined, this will use xmlXPathCmpNodesExt() instead of
70* xmlXPathCmpNodes(). The new function is optimized comparison of
71* non-element nodes; actually it will speed up comparison only if
72* xmlXPathOrderDocElems() was called in order to index the elements of
73* a tree in document order; Libxslt does such an indexing, thus it will
74* benefit from this optimization.
75*/
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000076#define XP_OPTIMIZED_NON_ELEM_COMPARISON
77
78/*
79* XP_OPTIMIZED_FILTER_FIRST:
80* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
81* in a way, that it stop evaluation at the first node.
82*/
83#define XP_OPTIMIZED_FILTER_FIRST
84
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000085/*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000086* XP_DEBUG_OBJ_USAGE:
87* Internal flag to enable tracking of how much XPath objects have been
88* created.
89*/
90/* #define XP_DEBUG_OBJ_USAGE */
91
92/*
William M. Brackd1757ab2004-10-02 22:07:48 +000093 * TODO:
94 * There are a few spots where some tests are done which depend upon ascii
95 * data. These should be enhanced for full UTF8 support (see particularly
96 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
97 */
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000098
William M. Brack21e4ef22005-01-02 09:53:13 +000099#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000100
101/************************************************************************
102 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000103 * Floating point stuff *
104 * *
105 ************************************************************************/
106
Daniel Veillardc0631a62001-09-20 13:56:06 +0000107#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +0000108#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +0000109#endif
Daniel Veillardcda96922001-08-21 10:56:31 +0000110#include "trionan.c"
111
Owen Taylor3473f882001-02-23 17:55:21 +0000112/*
Owen Taylor3473f882001-02-23 17:55:21 +0000113 * The lack of portability of this section of the libc is annoying !
114 */
115double xmlXPathNAN = 0;
116double xmlXPathPINF = 1;
117double xmlXPathNINF = -1;
Daniel Veillard24505b02005-07-28 23:49:35 +0000118static double xmlXPathNZERO = 0; /* not exported from headers */
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000119static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000120
Owen Taylor3473f882001-02-23 17:55:21 +0000121/**
122 * xmlXPathInit:
123 *
124 * Initialize the XPath environment
125 */
126void
127xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000128 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +0000129
Bjorn Reese45029602001-08-21 09:23:53 +0000130 xmlXPathPINF = trio_pinf();
131 xmlXPathNINF = trio_ninf();
132 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000133 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +0000134
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000135 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000136}
137
Daniel Veillardcda96922001-08-21 10:56:31 +0000138/**
139 * xmlXPathIsNaN:
140 * @val: a double value
141 *
142 * Provides a portable isnan() function to detect whether a double
143 * is a NotaNumber. Based on trio code
144 * http://sourceforge.net/projects/ctrio/
145 *
146 * Returns 1 if the value is a NaN, 0 otherwise
147 */
148int
149xmlXPathIsNaN(double val) {
150 return(trio_isnan(val));
151}
152
153/**
154 * xmlXPathIsInf:
155 * @val: a double value
156 *
157 * Provides a portable isinf() function to detect whether a double
158 * is a +Infinite or -Infinite. Based on trio code
159 * http://sourceforge.net/projects/ctrio/
160 *
161 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
162 */
163int
164xmlXPathIsInf(double val) {
165 return(trio_isinf(val));
166}
167
Daniel Veillard4432df22003-09-28 18:58:27 +0000168#endif /* SCHEMAS or XPATH */
169#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000170/**
171 * xmlXPathGetSign:
172 * @val: a double value
173 *
174 * Provides a portable function to detect the sign of a double
175 * Modified from trio code
176 * http://sourceforge.net/projects/ctrio/
177 *
178 * Returns 1 if the value is Negative, 0 if positive
179 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000180static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000181xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000182 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000183}
184
185
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000186/*
187 * TODO: when compatibility allows remove all "fake node libxslt" strings
188 * the test should just be name[0] = ' '
189 */
190/* #define DEBUG */
191/* #define DEBUG_STEP */
192/* #define DEBUG_STEP_NTH */
193/* #define DEBUG_EXPR */
194/* #define DEBUG_EVAL_COUNTS */
195
196static xmlNs xmlXPathXMLNamespaceStruct = {
197 NULL,
198 XML_NAMESPACE_DECL,
199 XML_XML_NAMESPACE,
200 BAD_CAST "xml",
201 NULL
202};
203static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
204#ifndef LIBXML_THREAD_ENABLED
205/*
206 * Optimizer is disabled only when threaded apps are detected while
207 * the library ain't compiled for thread safety.
208 */
209static int xmlXPathDisableOptimizer = 0;
210#endif
211
Owen Taylor3473f882001-02-23 17:55:21 +0000212/************************************************************************
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000213 * *
214 * Error handling routines *
215 * *
216 ************************************************************************/
217
Daniel Veillard24505b02005-07-28 23:49:35 +0000218/**
219 * XP_ERRORNULL:
220 * @X: the error code
221 *
222 * Macro to raise an XPath error and return NULL.
223 */
224#define XP_ERRORNULL(X) \
225 { xmlXPathErr(ctxt, X); return(NULL); }
226
William M. Brack08171912003-12-29 02:52:11 +0000227/*
228 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
229 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000230static const char *xmlXPathErrorMessages[] = {
231 "Ok\n",
232 "Number encoding\n",
233 "Unfinished literal\n",
234 "Start of literal\n",
235 "Expected $ for variable reference\n",
236 "Undefined variable\n",
237 "Invalid predicate\n",
238 "Invalid expression\n",
239 "Missing closing curly brace\n",
240 "Unregistered function\n",
241 "Invalid operand\n",
242 "Invalid type\n",
243 "Invalid number of arguments\n",
244 "Invalid context size\n",
245 "Invalid context position\n",
246 "Memory allocation error\n",
247 "Syntax error\n",
248 "Resource error\n",
249 "Sub resource error\n",
250 "Undefined namespace prefix\n",
251 "Encoding error\n",
Daniel Veillard57b25162004-11-06 14:50:18 +0000252 "Char out of XML range\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000253 "Invalid or incomplete context\n",
254 "?? Unknown error ??\n" /* Must be last in the list! */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000255};
William M. Brackcd65bc92005-01-06 09:39:18 +0000256#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
257 sizeof(xmlXPathErrorMessages[0])) - 1)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000258/**
259 * xmlXPathErrMemory:
260 * @ctxt: an XPath context
261 * @extra: extra informations
262 *
263 * Handle a redefinition of attribute error
264 */
265static void
266xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
267{
268 if (ctxt != NULL) {
269 if (extra) {
270 xmlChar buf[200];
271
272 xmlStrPrintf(buf, 200,
273 BAD_CAST "Memory allocation failed : %s\n",
274 extra);
275 ctxt->lastError.message = (char *) xmlStrdup(buf);
276 } else {
277 ctxt->lastError.message = (char *)
278 xmlStrdup(BAD_CAST "Memory allocation failed\n");
279 }
280 ctxt->lastError.domain = XML_FROM_XPATH;
281 ctxt->lastError.code = XML_ERR_NO_MEMORY;
282 if (ctxt->error != NULL)
283 ctxt->error(ctxt->userData, &ctxt->lastError);
284 } else {
285 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000286 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000287 NULL, NULL, XML_FROM_XPATH,
288 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
289 extra, NULL, NULL, 0, 0,
290 "Memory allocation failed : %s\n", extra);
291 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000292 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000293 NULL, NULL, XML_FROM_XPATH,
294 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
295 NULL, NULL, NULL, 0, 0,
296 "Memory allocation failed\n");
297 }
298}
299
300/**
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000301 * xmlXPathPErrMemory:
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000302 * @ctxt: an XPath parser context
303 * @extra: extra informations
304 *
305 * Handle a redefinition of attribute error
306 */
307static void
308xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
309{
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000310 if (ctxt == NULL)
311 xmlXPathErrMemory(NULL, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000312 else {
313 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000314 xmlXPathErrMemory(ctxt->context, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000315 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000316}
317
318/**
319 * xmlXPathErr:
320 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000321 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000322 *
William M. Brackcd65bc92005-01-06 09:39:18 +0000323 * Handle an XPath error
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000324 */
325void
326xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
327{
William M. Brackcd65bc92005-01-06 09:39:18 +0000328 if ((error < 0) || (error > MAXERRNO))
329 error = MAXERRNO;
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000330 if (ctxt == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000331 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000332 NULL, NULL, XML_FROM_XPATH,
333 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
334 XML_ERR_ERROR, NULL, 0,
335 NULL, NULL, NULL, 0, 0,
336 xmlXPathErrorMessages[error]);
337 return;
338 }
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000339 ctxt->error = error;
340 if (ctxt->context == NULL) {
341 __xmlRaiseError(NULL, NULL, NULL,
342 NULL, NULL, XML_FROM_XPATH,
343 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
344 XML_ERR_ERROR, NULL, 0,
345 (const char *) ctxt->base, NULL, NULL,
346 ctxt->cur - ctxt->base, 0,
347 xmlXPathErrorMessages[error]);
348 return;
349 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +0000350
351 /* cleanup current last error */
352 xmlResetError(&ctxt->context->lastError);
353
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000354 ctxt->context->lastError.domain = XML_FROM_XPATH;
355 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
356 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000357 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000358 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
359 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
360 ctxt->context->lastError.node = ctxt->context->debugNode;
361 if (ctxt->context->error != NULL) {
362 ctxt->context->error(ctxt->context->userData,
363 &ctxt->context->lastError);
364 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000365 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000366 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
367 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
368 XML_ERR_ERROR, NULL, 0,
369 (const char *) ctxt->base, NULL, NULL,
370 ctxt->cur - ctxt->base, 0,
371 xmlXPathErrorMessages[error]);
372 }
373
374}
375
376/**
377 * xmlXPatherror:
378 * @ctxt: the XPath Parser context
379 * @file: the file name
380 * @line: the line number
381 * @no: the error number
382 *
383 * Formats an error message.
384 */
385void
386xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
387 int line ATTRIBUTE_UNUSED, int no) {
388 xmlXPathErr(ctxt, no);
389}
390
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000391/************************************************************************
392 * *
393 * Utilities *
394 * *
395 ************************************************************************/
396
397/**
398 * xsltPointerList:
399 *
400 * Pointer-list for various purposes.
401 */
402typedef struct _xmlPointerList xmlPointerList;
403typedef xmlPointerList *xmlPointerListPtr;
404struct _xmlPointerList {
405 void **items;
406 int number;
407 int size;
408};
409/*
410* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
411* and here, we should make the functions public.
412*/
413static int
414xmlPointerListAddSize(xmlPointerListPtr list,
415 void *item,
416 int initialSize)
417{
418 if (list->items == NULL) {
419 if (initialSize <= 0)
420 initialSize = 1;
421 list->items = (void **) xmlMalloc(
422 initialSize * sizeof(void *));
423 if (list->items == NULL) {
424 xmlXPathErrMemory(NULL,
425 "xmlPointerListCreate: allocating item\n");
426 return(-1);
427 }
428 list->number = 0;
429 list->size = initialSize;
430 } else if (list->size <= list->number) {
431 list->size *= 2;
432 list->items = (void **) xmlRealloc(list->items,
433 list->size * sizeof(void *));
434 if (list->items == NULL) {
435 xmlXPathErrMemory(NULL,
436 "xmlPointerListCreate: re-allocating item\n");
437 list->size = 0;
438 return(-1);
439 }
440 }
441 list->items[list->number++] = item;
442 return(0);
443}
444
445/**
446 * xsltPointerListCreate:
447 *
448 * Creates an xsltPointerList structure.
449 *
450 * Returns a xsltPointerList structure or NULL in case of an error.
451 */
452static xmlPointerListPtr
453xmlPointerListCreate(int initialSize)
454{
455 xmlPointerListPtr ret;
456
457 ret = xmlMalloc(sizeof(xmlPointerList));
458 if (ret == NULL) {
459 xmlXPathErrMemory(NULL,
460 "xmlPointerListCreate: allocating item\n");
461 return (NULL);
462 }
463 memset(ret, 0, sizeof(xmlPointerList));
464 if (initialSize > 0) {
465 xmlPointerListAddSize(ret, NULL, initialSize);
466 ret->number = 0;
467 }
468 return (ret);
469}
470
471/**
472 * xsltPointerListFree:
473 *
474 * Frees the xsltPointerList structure. This does not free
475 * the content of the list.
476 */
477static void
478xmlPointerListFree(xmlPointerListPtr list)
479{
480 if (list == NULL)
481 return;
482 if (list->items != NULL)
483 xmlFree(list->items);
484 xmlFree(list);
485}
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000486
487/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000488 * *
489 * Parser Types *
490 * *
491 ************************************************************************/
492
493/*
494 * Types are private:
495 */
496
497typedef enum {
498 XPATH_OP_END=0,
499 XPATH_OP_AND,
500 XPATH_OP_OR,
501 XPATH_OP_EQUAL,
502 XPATH_OP_CMP,
503 XPATH_OP_PLUS,
504 XPATH_OP_MULT,
505 XPATH_OP_UNION,
506 XPATH_OP_ROOT,
507 XPATH_OP_NODE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000508 XPATH_OP_RESET, /* 10 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000509 XPATH_OP_COLLECT,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000510 XPATH_OP_VALUE, /* 12 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000511 XPATH_OP_VARIABLE,
512 XPATH_OP_FUNCTION,
513 XPATH_OP_ARG,
514 XPATH_OP_PREDICATE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000515 XPATH_OP_FILTER, /* 17 */
516 XPATH_OP_SORT /* 18 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000517#ifdef LIBXML_XPTR_ENABLED
518 ,XPATH_OP_RANGETO
519#endif
520} xmlXPathOp;
521
522typedef enum {
523 AXIS_ANCESTOR = 1,
524 AXIS_ANCESTOR_OR_SELF,
525 AXIS_ATTRIBUTE,
526 AXIS_CHILD,
527 AXIS_DESCENDANT,
528 AXIS_DESCENDANT_OR_SELF,
529 AXIS_FOLLOWING,
530 AXIS_FOLLOWING_SIBLING,
531 AXIS_NAMESPACE,
532 AXIS_PARENT,
533 AXIS_PRECEDING,
534 AXIS_PRECEDING_SIBLING,
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +0000535 AXIS_SELF
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000536} xmlXPathAxisVal;
537
538typedef enum {
539 NODE_TEST_NONE = 0,
540 NODE_TEST_TYPE = 1,
541 NODE_TEST_PI = 2,
542 NODE_TEST_ALL = 3,
543 NODE_TEST_NS = 4,
544 NODE_TEST_NAME = 5
545} xmlXPathTestVal;
546
547typedef enum {
548 NODE_TYPE_NODE = 0,
549 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
550 NODE_TYPE_TEXT = XML_TEXT_NODE,
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +0000551 NODE_TYPE_PI = XML_PI_NODE
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000552} xmlXPathTypeVal;
553
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +0000554#define XP_REWRITE_DOS_CHILD_ELEM 1
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000555
556typedef struct _xmlXPathStepOp xmlXPathStepOp;
557typedef xmlXPathStepOp *xmlXPathStepOpPtr;
558struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000559 xmlXPathOp op; /* The identifier of the operation */
560 int ch1; /* First child */
561 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000562 int value;
563 int value2;
564 int value3;
565 void *value4;
566 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000567 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000568 void *cacheURI;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +0000569 int rewriteType;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000570};
571
572struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000573 int nbStep; /* Number of steps in this expression */
574 int maxStep; /* Maximum number of steps allocated */
575 xmlXPathStepOp *steps; /* ops for computation of this expression */
576 int last; /* index of last step in expression */
577 xmlChar *expr; /* the expression being computed */
Daniel Veillard4773df22004-01-23 13:15:13 +0000578 xmlDictPtr dict; /* the dictionnary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000579#ifdef DEBUG_EVAL_COUNTS
580 int nb;
581 xmlChar *string;
582#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000583#ifdef XPATH_STREAMING
584 xmlPatternPtr stream;
585#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000586};
587
588/************************************************************************
589 * *
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000590 * Forward declarations *
591 * *
592 ************************************************************************/
593static void
594xmlXPathFreeValueTree(xmlNodeSetPtr obj);
595static void
596xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
597static int
598xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
599 xmlXPathStepOpPtr op, xmlNodePtr *first);
600static int
601xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +0000602 xmlXPathStepOpPtr op,
603 int isPredicate);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000604
605/************************************************************************
606 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000607 * Parser Type functions *
608 * *
609 ************************************************************************/
610
611/**
612 * xmlXPathNewCompExpr:
613 *
614 * Create a new Xpath component
615 *
616 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
617 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000618static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000619xmlXPathNewCompExpr(void) {
620 xmlXPathCompExprPtr cur;
621
622 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
623 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000624 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000625 return(NULL);
626 }
627 memset(cur, 0, sizeof(xmlXPathCompExpr));
628 cur->maxStep = 10;
629 cur->nbStep = 0;
630 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
631 sizeof(xmlXPathStepOp));
632 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000633 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000634 xmlFree(cur);
635 return(NULL);
636 }
637 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
638 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000639#ifdef DEBUG_EVAL_COUNTS
640 cur->nb = 0;
641#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000642 return(cur);
643}
644
645/**
646 * xmlXPathFreeCompExpr:
647 * @comp: an XPATH comp
648 *
649 * Free up the memory allocated by @comp
650 */
651void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000652xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
653{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000654 xmlXPathStepOpPtr op;
655 int i;
656
657 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000658 return;
Daniel Veillard4773df22004-01-23 13:15:13 +0000659 if (comp->dict == NULL) {
660 for (i = 0; i < comp->nbStep; i++) {
661 op = &comp->steps[i];
662 if (op->value4 != NULL) {
663 if (op->op == XPATH_OP_VALUE)
664 xmlXPathFreeObject(op->value4);
665 else
666 xmlFree(op->value4);
667 }
668 if (op->value5 != NULL)
669 xmlFree(op->value5);
670 }
671 } else {
672 for (i = 0; i < comp->nbStep; i++) {
673 op = &comp->steps[i];
674 if (op->value4 != NULL) {
675 if (op->op == XPATH_OP_VALUE)
676 xmlXPathFreeObject(op->value4);
677 }
678 }
679 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000680 }
681 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000682 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000683 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000684#ifdef DEBUG_EVAL_COUNTS
685 if (comp->string != NULL) {
686 xmlFree(comp->string);
687 }
688#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000689#ifdef XPATH_STREAMING
690 if (comp->stream != NULL) {
691 xmlFreePatternList(comp->stream);
692 }
693#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000694 if (comp->expr != NULL) {
695 xmlFree(comp->expr);
696 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000697
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000698 xmlFree(comp);
699}
700
701/**
702 * xmlXPathCompExprAdd:
703 * @comp: the compiled expression
704 * @ch1: first child index
705 * @ch2: second child index
706 * @op: an op
707 * @value: the first int value
708 * @value2: the second int value
709 * @value3: the third int value
710 * @value4: the first string value
711 * @value5: the second string value
712 *
William M. Brack08171912003-12-29 02:52:11 +0000713 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000714 *
715 * Returns -1 in case of failure, the index otherwise
716 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000717static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000718xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
719 xmlXPathOp op, int value,
720 int value2, int value3, void *value4, void *value5) {
721 if (comp->nbStep >= comp->maxStep) {
722 xmlXPathStepOp *real;
723
724 comp->maxStep *= 2;
725 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
726 comp->maxStep * sizeof(xmlXPathStepOp));
727 if (real == NULL) {
728 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000729 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000730 return(-1);
731 }
732 comp->steps = real;
733 }
734 comp->last = comp->nbStep;
Kasimier T. Buchcik6422d912006-06-26 14:31:53 +0000735 comp->steps[comp->nbStep].rewriteType = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000736 comp->steps[comp->nbStep].ch1 = ch1;
737 comp->steps[comp->nbStep].ch2 = ch2;
738 comp->steps[comp->nbStep].op = op;
739 comp->steps[comp->nbStep].value = value;
740 comp->steps[comp->nbStep].value2 = value2;
741 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +0000742 if ((comp->dict != NULL) &&
743 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
744 (op == XPATH_OP_COLLECT))) {
745 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000746 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000747 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000748 xmlFree(value4);
749 } else
750 comp->steps[comp->nbStep].value4 = NULL;
751 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000752 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000753 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000754 xmlFree(value5);
755 } else
756 comp->steps[comp->nbStep].value5 = NULL;
757 } else {
758 comp->steps[comp->nbStep].value4 = value4;
759 comp->steps[comp->nbStep].value5 = value5;
760 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000761 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000762 return(comp->nbStep++);
763}
764
Daniel Veillardf06307e2001-07-03 10:35:50 +0000765/**
766 * xmlXPathCompSwap:
767 * @comp: the compiled expression
768 * @op: operation index
769 *
770 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000771 */
772static void
773xmlXPathCompSwap(xmlXPathStepOpPtr op) {
774 int tmp;
775
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000776#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000777 /*
778 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +0000779 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +0000780 * application
781 */
782 if (xmlXPathDisableOptimizer)
783 return;
784#endif
785
Daniel Veillardf06307e2001-07-03 10:35:50 +0000786 tmp = op->ch1;
787 op->ch1 = op->ch2;
788 op->ch2 = tmp;
789}
790
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000791#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
792 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
793 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000794#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
795 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
796 (op), (val), (val2), (val3), (val4), (val5))
797
798#define PUSH_LEAVE_EXPR(op, val, val2) \
799xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
800
801#define PUSH_UNARY_EXPR(op, ch, val, val2) \
802xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
803
804#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +0000805xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
806 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000807
808/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000809 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000810 * XPath object cache structures *
811 * *
812 ************************************************************************/
813
814/* #define XP_DEFAULT_CACHE_ON */
815
Kasimier T. Buchcik58694692006-05-31 12:37:28 +0000816#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000817
Kasimier T. Buchcik58694692006-05-31 12:37:28 +0000818typedef struct _xmlXPathContextCache xmlXPathContextCache;
819typedef xmlXPathContextCache *xmlXPathContextCachePtr;
820struct _xmlXPathContextCache {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +0000821 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
822 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
823 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
824 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
825 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000826 int maxNodeset;
827 int maxString;
828 int maxBoolean;
829 int maxNumber;
830 int maxMisc;
831#ifdef XP_DEBUG_OBJ_USAGE
832 int dbgCachedAll;
833 int dbgCachedNodeset;
834 int dbgCachedString;
835 int dbgCachedBool;
836 int dbgCachedNumber;
837 int dbgCachedPoint;
838 int dbgCachedRange;
839 int dbgCachedLocset;
840 int dbgCachedUsers;
841 int dbgCachedXSLTTree;
842 int dbgCachedUndefined;
843
844
845 int dbgReusedAll;
846 int dbgReusedNodeset;
847 int dbgReusedString;
848 int dbgReusedBool;
849 int dbgReusedNumber;
850 int dbgReusedPoint;
851 int dbgReusedRange;
852 int dbgReusedLocset;
853 int dbgReusedUsers;
854 int dbgReusedXSLTTree;
855 int dbgReusedUndefined;
856
857#endif
858};
859
860/************************************************************************
861 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000862 * Debugging related functions *
863 * *
864 ************************************************************************/
865
Owen Taylor3473f882001-02-23 17:55:21 +0000866#define STRANGE \
867 xmlGenericError(xmlGenericErrorContext, \
868 "Internal error at %s:%d\n", \
869 __FILE__, __LINE__);
870
871#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000872static void
873xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000874 int i;
875 char shift[100];
876
877 for (i = 0;((i < depth) && (i < 25));i++)
878 shift[2 * i] = shift[2 * i + 1] = ' ';
879 shift[2 * i] = shift[2 * i + 1] = 0;
880 if (cur == NULL) {
881 fprintf(output, shift);
882 fprintf(output, "Node is NULL !\n");
883 return;
884
885 }
886
887 if ((cur->type == XML_DOCUMENT_NODE) ||
888 (cur->type == XML_HTML_DOCUMENT_NODE)) {
889 fprintf(output, shift);
890 fprintf(output, " /\n");
891 } else if (cur->type == XML_ATTRIBUTE_NODE)
892 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
893 else
894 xmlDebugDumpOneNode(output, cur, depth);
895}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000896static void
897xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000898 xmlNodePtr tmp;
899 int i;
900 char shift[100];
901
902 for (i = 0;((i < depth) && (i < 25));i++)
903 shift[2 * i] = shift[2 * i + 1] = ' ';
904 shift[2 * i] = shift[2 * i + 1] = 0;
905 if (cur == NULL) {
906 fprintf(output, shift);
907 fprintf(output, "Node is NULL !\n");
908 return;
909
910 }
911
912 while (cur != NULL) {
913 tmp = cur;
914 cur = cur->next;
915 xmlDebugDumpOneNode(output, tmp, depth);
916 }
917}
Owen Taylor3473f882001-02-23 17:55:21 +0000918
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000919static void
920xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000921 int i;
922 char shift[100];
923
924 for (i = 0;((i < depth) && (i < 25));i++)
925 shift[2 * i] = shift[2 * i + 1] = ' ';
926 shift[2 * i] = shift[2 * i + 1] = 0;
927
928 if (cur == NULL) {
929 fprintf(output, shift);
930 fprintf(output, "NodeSet is NULL !\n");
931 return;
932
933 }
934
Daniel Veillard911f49a2001-04-07 15:39:35 +0000935 if (cur != NULL) {
936 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
937 for (i = 0;i < cur->nodeNr;i++) {
938 fprintf(output, shift);
939 fprintf(output, "%d", i + 1);
940 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
941 }
Owen Taylor3473f882001-02-23 17:55:21 +0000942 }
943}
944
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000945static void
946xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000947 int i;
948 char shift[100];
949
950 for (i = 0;((i < depth) && (i < 25));i++)
951 shift[2 * i] = shift[2 * i + 1] = ' ';
952 shift[2 * i] = shift[2 * i + 1] = 0;
953
954 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
955 fprintf(output, shift);
956 fprintf(output, "Value Tree is NULL !\n");
957 return;
958
959 }
960
961 fprintf(output, shift);
962 fprintf(output, "%d", i + 1);
963 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
964}
Owen Taylor3473f882001-02-23 17:55:21 +0000965#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000966static void
967xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000968 int i;
969 char shift[100];
970
971 for (i = 0;((i < depth) && (i < 25));i++)
972 shift[2 * i] = shift[2 * i + 1] = ' ';
973 shift[2 * i] = shift[2 * i + 1] = 0;
974
975 if (cur == NULL) {
976 fprintf(output, shift);
977 fprintf(output, "LocationSet is NULL !\n");
978 return;
979
980 }
981
982 for (i = 0;i < cur->locNr;i++) {
983 fprintf(output, shift);
984 fprintf(output, "%d : ", i + 1);
985 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
986 }
987}
Daniel Veillard017b1082001-06-21 11:20:21 +0000988#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000989
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000990/**
991 * xmlXPathDebugDumpObject:
992 * @output: the FILE * to dump the output
993 * @cur: the object to inspect
994 * @depth: indentation level
995 *
996 * Dump the content of the object for debugging purposes
997 */
998void
999xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001000 int i;
1001 char shift[100];
1002
Daniel Veillarda82b1822004-11-08 16:24:57 +00001003 if (output == NULL) return;
1004
Owen Taylor3473f882001-02-23 17:55:21 +00001005 for (i = 0;((i < depth) && (i < 25));i++)
1006 shift[2 * i] = shift[2 * i + 1] = ' ';
1007 shift[2 * i] = shift[2 * i + 1] = 0;
1008
Kasimier T. Buchcik97258712006-01-05 12:30:43 +00001009
1010 fprintf(output, shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001011
1012 if (cur == NULL) {
1013 fprintf(output, "Object is empty (NULL)\n");
1014 return;
1015 }
1016 switch(cur->type) {
1017 case XPATH_UNDEFINED:
1018 fprintf(output, "Object is uninitialized\n");
1019 break;
1020 case XPATH_NODESET:
1021 fprintf(output, "Object is a Node Set :\n");
1022 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1023 break;
1024 case XPATH_XSLT_TREE:
1025 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001026 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +00001027 break;
1028 case XPATH_BOOLEAN:
1029 fprintf(output, "Object is a Boolean : ");
1030 if (cur->boolval) fprintf(output, "true\n");
1031 else fprintf(output, "false\n");
1032 break;
1033 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +00001034 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001035 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001036 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001037 break;
1038 case -1:
1039 fprintf(output, "Object is a number : -Infinity\n");
1040 break;
1041 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001042 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001043 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001044 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1045 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001046 } else {
1047 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1048 }
1049 }
Owen Taylor3473f882001-02-23 17:55:21 +00001050 break;
1051 case XPATH_STRING:
1052 fprintf(output, "Object is a string : ");
1053 xmlDebugDumpString(output, cur->stringval);
1054 fprintf(output, "\n");
1055 break;
1056 case XPATH_POINT:
1057 fprintf(output, "Object is a point : index %d in node", cur->index);
1058 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1059 fprintf(output, "\n");
1060 break;
1061 case XPATH_RANGE:
1062 if ((cur->user2 == NULL) ||
1063 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1064 fprintf(output, "Object is a collapsed range :\n");
1065 fprintf(output, shift);
1066 if (cur->index >= 0)
1067 fprintf(output, "index %d in ", cur->index);
1068 fprintf(output, "node\n");
1069 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1070 depth + 1);
1071 } else {
1072 fprintf(output, "Object is a range :\n");
1073 fprintf(output, shift);
1074 fprintf(output, "From ");
1075 if (cur->index >= 0)
1076 fprintf(output, "index %d in ", cur->index);
1077 fprintf(output, "node\n");
1078 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1079 depth + 1);
1080 fprintf(output, shift);
1081 fprintf(output, "To ");
1082 if (cur->index2 >= 0)
1083 fprintf(output, "index %d in ", cur->index2);
1084 fprintf(output, "node\n");
1085 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1086 depth + 1);
1087 fprintf(output, "\n");
1088 }
1089 break;
1090 case XPATH_LOCATIONSET:
1091#if defined(LIBXML_XPTR_ENABLED)
1092 fprintf(output, "Object is a Location Set:\n");
1093 xmlXPathDebugDumpLocationSet(output,
1094 (xmlLocationSetPtr) cur->user, depth);
1095#endif
1096 break;
1097 case XPATH_USERS:
1098 fprintf(output, "Object is user defined\n");
1099 break;
1100 }
1101}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001102
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001103static void
1104xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001105 xmlXPathStepOpPtr op, int depth) {
1106 int i;
1107 char shift[100];
1108
1109 for (i = 0;((i < depth) && (i < 25));i++)
1110 shift[2 * i] = shift[2 * i + 1] = ' ';
1111 shift[2 * i] = shift[2 * i + 1] = 0;
1112
1113 fprintf(output, shift);
1114 if (op == NULL) {
1115 fprintf(output, "Step is NULL\n");
1116 return;
1117 }
1118 switch (op->op) {
1119 case XPATH_OP_END:
1120 fprintf(output, "END"); break;
1121 case XPATH_OP_AND:
1122 fprintf(output, "AND"); break;
1123 case XPATH_OP_OR:
1124 fprintf(output, "OR"); break;
1125 case XPATH_OP_EQUAL:
1126 if (op->value)
1127 fprintf(output, "EQUAL =");
1128 else
1129 fprintf(output, "EQUAL !=");
1130 break;
1131 case XPATH_OP_CMP:
1132 if (op->value)
1133 fprintf(output, "CMP <");
1134 else
1135 fprintf(output, "CMP >");
1136 if (!op->value2)
1137 fprintf(output, "=");
1138 break;
1139 case XPATH_OP_PLUS:
1140 if (op->value == 0)
1141 fprintf(output, "PLUS -");
1142 else if (op->value == 1)
1143 fprintf(output, "PLUS +");
1144 else if (op->value == 2)
1145 fprintf(output, "PLUS unary -");
1146 else if (op->value == 3)
1147 fprintf(output, "PLUS unary - -");
1148 break;
1149 case XPATH_OP_MULT:
1150 if (op->value == 0)
1151 fprintf(output, "MULT *");
1152 else if (op->value == 1)
1153 fprintf(output, "MULT div");
1154 else
1155 fprintf(output, "MULT mod");
1156 break;
1157 case XPATH_OP_UNION:
1158 fprintf(output, "UNION"); break;
1159 case XPATH_OP_ROOT:
1160 fprintf(output, "ROOT"); break;
1161 case XPATH_OP_NODE:
1162 fprintf(output, "NODE"); break;
1163 case XPATH_OP_RESET:
1164 fprintf(output, "RESET"); break;
1165 case XPATH_OP_SORT:
1166 fprintf(output, "SORT"); break;
1167 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +00001168 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1169 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1170 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001171 const xmlChar *prefix = op->value4;
1172 const xmlChar *name = op->value5;
1173
1174 fprintf(output, "COLLECT ");
1175 switch (axis) {
1176 case AXIS_ANCESTOR:
1177 fprintf(output, " 'ancestors' "); break;
1178 case AXIS_ANCESTOR_OR_SELF:
1179 fprintf(output, " 'ancestors-or-self' "); break;
1180 case AXIS_ATTRIBUTE:
1181 fprintf(output, " 'attributes' "); break;
1182 case AXIS_CHILD:
1183 fprintf(output, " 'child' "); break;
1184 case AXIS_DESCENDANT:
1185 fprintf(output, " 'descendant' "); break;
1186 case AXIS_DESCENDANT_OR_SELF:
1187 fprintf(output, " 'descendant-or-self' "); break;
1188 case AXIS_FOLLOWING:
1189 fprintf(output, " 'following' "); break;
1190 case AXIS_FOLLOWING_SIBLING:
1191 fprintf(output, " 'following-siblings' "); break;
1192 case AXIS_NAMESPACE:
1193 fprintf(output, " 'namespace' "); break;
1194 case AXIS_PARENT:
1195 fprintf(output, " 'parent' "); break;
1196 case AXIS_PRECEDING:
1197 fprintf(output, " 'preceding' "); break;
1198 case AXIS_PRECEDING_SIBLING:
1199 fprintf(output, " 'preceding-sibling' "); break;
1200 case AXIS_SELF:
1201 fprintf(output, " 'self' "); break;
1202 }
1203 switch (test) {
1204 case NODE_TEST_NONE:
1205 fprintf(output, "'none' "); break;
1206 case NODE_TEST_TYPE:
1207 fprintf(output, "'type' "); break;
1208 case NODE_TEST_PI:
1209 fprintf(output, "'PI' "); break;
1210 case NODE_TEST_ALL:
1211 fprintf(output, "'all' "); break;
1212 case NODE_TEST_NS:
1213 fprintf(output, "'namespace' "); break;
1214 case NODE_TEST_NAME:
1215 fprintf(output, "'name' "); break;
1216 }
1217 switch (type) {
1218 case NODE_TYPE_NODE:
1219 fprintf(output, "'node' "); break;
1220 case NODE_TYPE_COMMENT:
1221 fprintf(output, "'comment' "); break;
1222 case NODE_TYPE_TEXT:
1223 fprintf(output, "'text' "); break;
1224 case NODE_TYPE_PI:
1225 fprintf(output, "'PI' "); break;
1226 }
1227 if (prefix != NULL)
1228 fprintf(output, "%s:", prefix);
1229 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001230 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001231 break;
1232
1233 }
1234 case XPATH_OP_VALUE: {
1235 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1236
1237 fprintf(output, "ELEM ");
1238 xmlXPathDebugDumpObject(output, object, 0);
1239 goto finish;
1240 }
1241 case XPATH_OP_VARIABLE: {
1242 const xmlChar *prefix = op->value5;
1243 const xmlChar *name = op->value4;
1244
1245 if (prefix != NULL)
1246 fprintf(output, "VARIABLE %s:%s", prefix, name);
1247 else
1248 fprintf(output, "VARIABLE %s", name);
1249 break;
1250 }
1251 case XPATH_OP_FUNCTION: {
1252 int nbargs = op->value;
1253 const xmlChar *prefix = op->value5;
1254 const xmlChar *name = op->value4;
1255
1256 if (prefix != NULL)
1257 fprintf(output, "FUNCTION %s:%s(%d args)",
1258 prefix, name, nbargs);
1259 else
1260 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1261 break;
1262 }
1263 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1264 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001265 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001266#ifdef LIBXML_XPTR_ENABLED
1267 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1268#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001269 default:
1270 fprintf(output, "UNKNOWN %d\n", op->op); return;
1271 }
1272 fprintf(output, "\n");
1273finish:
1274 if (op->ch1 >= 0)
1275 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1276 if (op->ch2 >= 0)
1277 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1278}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001279
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001280/**
1281 * xmlXPathDebugDumpCompExpr:
1282 * @output: the FILE * for the output
1283 * @comp: the precompiled XPath expression
1284 * @depth: the indentation level.
1285 *
1286 * Dumps the tree of the compiled XPath expression.
1287 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001288void
1289xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1290 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001291 int i;
1292 char shift[100];
1293
Daniel Veillarda82b1822004-11-08 16:24:57 +00001294 if ((output == NULL) || (comp == NULL)) return;
1295
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001296 for (i = 0;((i < depth) && (i < 25));i++)
1297 shift[2 * i] = shift[2 * i + 1] = ' ';
1298 shift[2 * i] = shift[2 * i + 1] = 0;
1299
1300 fprintf(output, shift);
1301
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001302 fprintf(output, "Compiled Expression : %d elements\n",
1303 comp->nbStep);
1304 i = comp->last;
1305 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1306}
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001307
1308#ifdef XP_DEBUG_OBJ_USAGE
1309
1310/*
1311* XPath object usage related debugging variables.
1312*/
1313static int xmlXPathDebugObjCounterUndefined = 0;
1314static int xmlXPathDebugObjCounterNodeset = 0;
1315static int xmlXPathDebugObjCounterBool = 0;
1316static int xmlXPathDebugObjCounterNumber = 0;
1317static int xmlXPathDebugObjCounterString = 0;
1318static int xmlXPathDebugObjCounterPoint = 0;
1319static int xmlXPathDebugObjCounterRange = 0;
1320static int xmlXPathDebugObjCounterLocset = 0;
1321static int xmlXPathDebugObjCounterUsers = 0;
1322static int xmlXPathDebugObjCounterXSLTTree = 0;
1323static int xmlXPathDebugObjCounterAll = 0;
1324
1325static int xmlXPathDebugObjTotalUndefined = 0;
1326static int xmlXPathDebugObjTotalNodeset = 0;
1327static int xmlXPathDebugObjTotalBool = 0;
1328static int xmlXPathDebugObjTotalNumber = 0;
1329static int xmlXPathDebugObjTotalString = 0;
1330static int xmlXPathDebugObjTotalPoint = 0;
1331static int xmlXPathDebugObjTotalRange = 0;
1332static int xmlXPathDebugObjTotalLocset = 0;
1333static int xmlXPathDebugObjTotalUsers = 0;
1334static int xmlXPathDebugObjTotalXSLTTree = 0;
1335static int xmlXPathDebugObjTotalAll = 0;
1336
1337static int xmlXPathDebugObjMaxUndefined = 0;
1338static int xmlXPathDebugObjMaxNodeset = 0;
1339static int xmlXPathDebugObjMaxBool = 0;
1340static int xmlXPathDebugObjMaxNumber = 0;
1341static int xmlXPathDebugObjMaxString = 0;
1342static int xmlXPathDebugObjMaxPoint = 0;
1343static int xmlXPathDebugObjMaxRange = 0;
1344static int xmlXPathDebugObjMaxLocset = 0;
1345static int xmlXPathDebugObjMaxUsers = 0;
1346static int xmlXPathDebugObjMaxXSLTTree = 0;
1347static int xmlXPathDebugObjMaxAll = 0;
1348
1349/* REVISIT TODO: Make this static when committing */
1350static void
1351xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1352{
1353 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001354 if (ctxt->cache != NULL) {
1355 xmlXPathContextCachePtr cache =
1356 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001357
1358 cache->dbgCachedAll = 0;
1359 cache->dbgCachedNodeset = 0;
1360 cache->dbgCachedString = 0;
1361 cache->dbgCachedBool = 0;
1362 cache->dbgCachedNumber = 0;
1363 cache->dbgCachedPoint = 0;
1364 cache->dbgCachedRange = 0;
1365 cache->dbgCachedLocset = 0;
1366 cache->dbgCachedUsers = 0;
1367 cache->dbgCachedXSLTTree = 0;
1368 cache->dbgCachedUndefined = 0;
1369
1370 cache->dbgReusedAll = 0;
1371 cache->dbgReusedNodeset = 0;
1372 cache->dbgReusedString = 0;
1373 cache->dbgReusedBool = 0;
1374 cache->dbgReusedNumber = 0;
1375 cache->dbgReusedPoint = 0;
1376 cache->dbgReusedRange = 0;
1377 cache->dbgReusedLocset = 0;
1378 cache->dbgReusedUsers = 0;
1379 cache->dbgReusedXSLTTree = 0;
1380 cache->dbgReusedUndefined = 0;
1381 }
1382 }
1383
1384 xmlXPathDebugObjCounterUndefined = 0;
1385 xmlXPathDebugObjCounterNodeset = 0;
1386 xmlXPathDebugObjCounterBool = 0;
1387 xmlXPathDebugObjCounterNumber = 0;
1388 xmlXPathDebugObjCounterString = 0;
1389 xmlXPathDebugObjCounterPoint = 0;
1390 xmlXPathDebugObjCounterRange = 0;
1391 xmlXPathDebugObjCounterLocset = 0;
1392 xmlXPathDebugObjCounterUsers = 0;
1393 xmlXPathDebugObjCounterXSLTTree = 0;
1394 xmlXPathDebugObjCounterAll = 0;
1395
1396 xmlXPathDebugObjTotalUndefined = 0;
1397 xmlXPathDebugObjTotalNodeset = 0;
1398 xmlXPathDebugObjTotalBool = 0;
1399 xmlXPathDebugObjTotalNumber = 0;
1400 xmlXPathDebugObjTotalString = 0;
1401 xmlXPathDebugObjTotalPoint = 0;
1402 xmlXPathDebugObjTotalRange = 0;
1403 xmlXPathDebugObjTotalLocset = 0;
1404 xmlXPathDebugObjTotalUsers = 0;
1405 xmlXPathDebugObjTotalXSLTTree = 0;
1406 xmlXPathDebugObjTotalAll = 0;
1407
1408 xmlXPathDebugObjMaxUndefined = 0;
1409 xmlXPathDebugObjMaxNodeset = 0;
1410 xmlXPathDebugObjMaxBool = 0;
1411 xmlXPathDebugObjMaxNumber = 0;
1412 xmlXPathDebugObjMaxString = 0;
1413 xmlXPathDebugObjMaxPoint = 0;
1414 xmlXPathDebugObjMaxRange = 0;
1415 xmlXPathDebugObjMaxLocset = 0;
1416 xmlXPathDebugObjMaxUsers = 0;
1417 xmlXPathDebugObjMaxXSLTTree = 0;
1418 xmlXPathDebugObjMaxAll = 0;
1419
1420}
1421
1422static void
1423xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1424 xmlXPathObjectType objType)
1425{
1426 int isCached = 0;
1427
1428 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001429 if (ctxt->cache != NULL) {
1430 xmlXPathContextCachePtr cache =
1431 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001432
1433 isCached = 1;
1434
1435 cache->dbgReusedAll++;
1436 switch (objType) {
1437 case XPATH_UNDEFINED:
1438 cache->dbgReusedUndefined++;
1439 break;
1440 case XPATH_NODESET:
1441 cache->dbgReusedNodeset++;
1442 break;
1443 case XPATH_BOOLEAN:
1444 cache->dbgReusedBool++;
1445 break;
1446 case XPATH_NUMBER:
1447 cache->dbgReusedNumber++;
1448 break;
1449 case XPATH_STRING:
1450 cache->dbgReusedString++;
1451 break;
1452 case XPATH_POINT:
1453 cache->dbgReusedPoint++;
1454 break;
1455 case XPATH_RANGE:
1456 cache->dbgReusedRange++;
1457 break;
1458 case XPATH_LOCATIONSET:
1459 cache->dbgReusedLocset++;
1460 break;
1461 case XPATH_USERS:
1462 cache->dbgReusedUsers++;
1463 break;
1464 case XPATH_XSLT_TREE:
1465 cache->dbgReusedXSLTTree++;
1466 break;
1467 default:
1468 break;
1469 }
1470 }
1471 }
1472
1473 switch (objType) {
1474 case XPATH_UNDEFINED:
1475 if (! isCached)
1476 xmlXPathDebugObjTotalUndefined++;
1477 xmlXPathDebugObjCounterUndefined++;
1478 if (xmlXPathDebugObjCounterUndefined >
1479 xmlXPathDebugObjMaxUndefined)
1480 xmlXPathDebugObjMaxUndefined =
1481 xmlXPathDebugObjCounterUndefined;
1482 break;
1483 case XPATH_NODESET:
1484 if (! isCached)
1485 xmlXPathDebugObjTotalNodeset++;
1486 xmlXPathDebugObjCounterNodeset++;
1487 if (xmlXPathDebugObjCounterNodeset >
1488 xmlXPathDebugObjMaxNodeset)
1489 xmlXPathDebugObjMaxNodeset =
1490 xmlXPathDebugObjCounterNodeset;
1491 break;
1492 case XPATH_BOOLEAN:
1493 if (! isCached)
1494 xmlXPathDebugObjTotalBool++;
1495 xmlXPathDebugObjCounterBool++;
1496 if (xmlXPathDebugObjCounterBool >
1497 xmlXPathDebugObjMaxBool)
1498 xmlXPathDebugObjMaxBool =
1499 xmlXPathDebugObjCounterBool;
1500 break;
1501 case XPATH_NUMBER:
1502 if (! isCached)
1503 xmlXPathDebugObjTotalNumber++;
1504 xmlXPathDebugObjCounterNumber++;
1505 if (xmlXPathDebugObjCounterNumber >
1506 xmlXPathDebugObjMaxNumber)
1507 xmlXPathDebugObjMaxNumber =
1508 xmlXPathDebugObjCounterNumber;
1509 break;
1510 case XPATH_STRING:
1511 if (! isCached)
1512 xmlXPathDebugObjTotalString++;
1513 xmlXPathDebugObjCounterString++;
1514 if (xmlXPathDebugObjCounterString >
1515 xmlXPathDebugObjMaxString)
1516 xmlXPathDebugObjMaxString =
1517 xmlXPathDebugObjCounterString;
1518 break;
1519 case XPATH_POINT:
1520 if (! isCached)
1521 xmlXPathDebugObjTotalPoint++;
1522 xmlXPathDebugObjCounterPoint++;
1523 if (xmlXPathDebugObjCounterPoint >
1524 xmlXPathDebugObjMaxPoint)
1525 xmlXPathDebugObjMaxPoint =
1526 xmlXPathDebugObjCounterPoint;
1527 break;
1528 case XPATH_RANGE:
1529 if (! isCached)
1530 xmlXPathDebugObjTotalRange++;
1531 xmlXPathDebugObjCounterRange++;
1532 if (xmlXPathDebugObjCounterRange >
1533 xmlXPathDebugObjMaxRange)
1534 xmlXPathDebugObjMaxRange =
1535 xmlXPathDebugObjCounterRange;
1536 break;
1537 case XPATH_LOCATIONSET:
1538 if (! isCached)
1539 xmlXPathDebugObjTotalLocset++;
1540 xmlXPathDebugObjCounterLocset++;
1541 if (xmlXPathDebugObjCounterLocset >
1542 xmlXPathDebugObjMaxLocset)
1543 xmlXPathDebugObjMaxLocset =
1544 xmlXPathDebugObjCounterLocset;
1545 break;
1546 case XPATH_USERS:
1547 if (! isCached)
1548 xmlXPathDebugObjTotalUsers++;
1549 xmlXPathDebugObjCounterUsers++;
1550 if (xmlXPathDebugObjCounterUsers >
1551 xmlXPathDebugObjMaxUsers)
1552 xmlXPathDebugObjMaxUsers =
1553 xmlXPathDebugObjCounterUsers;
1554 break;
1555 case XPATH_XSLT_TREE:
1556 if (! isCached)
1557 xmlXPathDebugObjTotalXSLTTree++;
1558 xmlXPathDebugObjCounterXSLTTree++;
1559 if (xmlXPathDebugObjCounterXSLTTree >
1560 xmlXPathDebugObjMaxXSLTTree)
1561 xmlXPathDebugObjMaxXSLTTree =
1562 xmlXPathDebugObjCounterXSLTTree;
1563 break;
1564 default:
1565 break;
1566 }
1567 if (! isCached)
1568 xmlXPathDebugObjTotalAll++;
1569 xmlXPathDebugObjCounterAll++;
1570 if (xmlXPathDebugObjCounterAll >
1571 xmlXPathDebugObjMaxAll)
1572 xmlXPathDebugObjMaxAll =
1573 xmlXPathDebugObjCounterAll;
1574}
1575
1576static void
1577xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1578 xmlXPathObjectType objType)
1579{
1580 int isCached = 0;
1581
1582 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001583 if (ctxt->cache != NULL) {
1584 xmlXPathContextCachePtr cache =
1585 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001586
1587 isCached = 1;
1588
1589 cache->dbgCachedAll++;
1590 switch (objType) {
1591 case XPATH_UNDEFINED:
1592 cache->dbgCachedUndefined++;
1593 break;
1594 case XPATH_NODESET:
1595 cache->dbgCachedNodeset++;
1596 break;
1597 case XPATH_BOOLEAN:
1598 cache->dbgCachedBool++;
1599 break;
1600 case XPATH_NUMBER:
1601 cache->dbgCachedNumber++;
1602 break;
1603 case XPATH_STRING:
1604 cache->dbgCachedString++;
1605 break;
1606 case XPATH_POINT:
1607 cache->dbgCachedPoint++;
1608 break;
1609 case XPATH_RANGE:
1610 cache->dbgCachedRange++;
1611 break;
1612 case XPATH_LOCATIONSET:
1613 cache->dbgCachedLocset++;
1614 break;
1615 case XPATH_USERS:
1616 cache->dbgCachedUsers++;
1617 break;
1618 case XPATH_XSLT_TREE:
1619 cache->dbgCachedXSLTTree++;
1620 break;
1621 default:
1622 break;
1623 }
1624
1625 }
1626 }
1627 switch (objType) {
1628 case XPATH_UNDEFINED:
1629 xmlXPathDebugObjCounterUndefined--;
1630 break;
1631 case XPATH_NODESET:
1632 xmlXPathDebugObjCounterNodeset--;
1633 break;
1634 case XPATH_BOOLEAN:
1635 xmlXPathDebugObjCounterBool--;
1636 break;
1637 case XPATH_NUMBER:
1638 xmlXPathDebugObjCounterNumber--;
1639 break;
1640 case XPATH_STRING:
1641 xmlXPathDebugObjCounterString--;
1642 break;
1643 case XPATH_POINT:
1644 xmlXPathDebugObjCounterPoint--;
1645 break;
1646 case XPATH_RANGE:
1647 xmlXPathDebugObjCounterRange--;
1648 break;
1649 case XPATH_LOCATIONSET:
1650 xmlXPathDebugObjCounterLocset--;
1651 break;
1652 case XPATH_USERS:
1653 xmlXPathDebugObjCounterUsers--;
1654 break;
1655 case XPATH_XSLT_TREE:
1656 xmlXPathDebugObjCounterXSLTTree--;
1657 break;
1658 default:
1659 break;
1660 }
1661 xmlXPathDebugObjCounterAll--;
1662}
1663
1664/* REVISIT TODO: Make this static when committing */
1665static void
1666xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
1667{
1668 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
1669 reqXSLTTree, reqUndefined;
1670 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
1671 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
1672 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
1673 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
1674 int leftObjs = xmlXPathDebugObjCounterAll;
1675
1676 reqAll = xmlXPathDebugObjTotalAll;
1677 reqNodeset = xmlXPathDebugObjTotalNodeset;
1678 reqString = xmlXPathDebugObjTotalString;
1679 reqBool = xmlXPathDebugObjTotalBool;
1680 reqNumber = xmlXPathDebugObjTotalNumber;
1681 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
1682 reqUndefined = xmlXPathDebugObjTotalUndefined;
1683
1684 printf("# XPath object usage:\n");
1685
1686 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001687 if (ctxt->cache != NULL) {
1688 xmlXPathContextCachePtr cache =
1689 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001690
1691 reAll = cache->dbgReusedAll;
1692 reqAll += reAll;
1693 reNodeset = cache->dbgReusedNodeset;
1694 reqNodeset += reNodeset;
1695 reString = cache->dbgReusedString;
1696 reqString += reString;
1697 reBool = cache->dbgReusedBool;
1698 reqBool += reBool;
1699 reNumber = cache->dbgReusedNumber;
1700 reqNumber += reNumber;
1701 reXSLTTree = cache->dbgReusedXSLTTree;
1702 reqXSLTTree += reXSLTTree;
1703 reUndefined = cache->dbgReusedUndefined;
1704 reqUndefined += reUndefined;
1705
1706 caAll = cache->dbgCachedAll;
1707 caBool = cache->dbgCachedBool;
1708 caNodeset = cache->dbgCachedNodeset;
1709 caString = cache->dbgCachedString;
1710 caNumber = cache->dbgCachedNumber;
1711 caXSLTTree = cache->dbgCachedXSLTTree;
1712 caUndefined = cache->dbgCachedUndefined;
1713
1714 if (cache->nodesetObjs)
1715 leftObjs -= cache->nodesetObjs->number;
1716 if (cache->stringObjs)
1717 leftObjs -= cache->stringObjs->number;
1718 if (cache->booleanObjs)
1719 leftObjs -= cache->booleanObjs->number;
1720 if (cache->numberObjs)
1721 leftObjs -= cache->numberObjs->number;
1722 if (cache->miscObjs)
1723 leftObjs -= cache->miscObjs->number;
1724 }
1725 }
1726
1727 printf("# all\n");
1728 printf("# total : %d\n", reqAll);
1729 printf("# left : %d\n", leftObjs);
1730 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
1731 printf("# reused : %d\n", reAll);
1732 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
1733
1734 printf("# node-sets\n");
1735 printf("# total : %d\n", reqNodeset);
1736 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
1737 printf("# reused : %d\n", reNodeset);
1738 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
1739
1740 printf("# strings\n");
1741 printf("# total : %d\n", reqString);
1742 printf("# created: %d\n", xmlXPathDebugObjTotalString);
1743 printf("# reused : %d\n", reString);
1744 printf("# max : %d\n", xmlXPathDebugObjMaxString);
1745
1746 printf("# booleans\n");
1747 printf("# total : %d\n", reqBool);
1748 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
1749 printf("# reused : %d\n", reBool);
1750 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
1751
1752 printf("# numbers\n");
1753 printf("# total : %d\n", reqNumber);
1754 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
1755 printf("# reused : %d\n", reNumber);
1756 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
1757
1758 printf("# XSLT result tree fragments\n");
1759 printf("# total : %d\n", reqXSLTTree);
1760 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
1761 printf("# reused : %d\n", reXSLTTree);
1762 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
1763
1764 printf("# undefined\n");
1765 printf("# total : %d\n", reqUndefined);
1766 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
1767 printf("# reused : %d\n", reUndefined);
1768 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
1769
1770}
1771
1772#endif /* XP_DEBUG_OBJ_USAGE */
1773
Daniel Veillard017b1082001-06-21 11:20:21 +00001774#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001775
1776/************************************************************************
1777 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001778 * XPath object caching *
1779 * *
1780 ************************************************************************/
1781
1782/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001783 * xmlXPathNewCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001784 *
1785 * Create a new object cache
1786 *
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001787 * Returns the xmlXPathCache just allocated.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001788 */
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001789static xmlXPathContextCachePtr
1790xmlXPathNewCache(void)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001791{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001792 xmlXPathContextCachePtr ret;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001793
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001794 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001795 if (ret == NULL) {
1796 xmlXPathErrMemory(NULL, "creating object cache\n");
1797 return(NULL);
1798 }
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001799 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001800 ret->maxNodeset = 100;
1801 ret->maxString = 100;
1802 ret->maxBoolean = 100;
1803 ret->maxNumber = 100;
1804 ret->maxMisc = 100;
1805 return(ret);
1806}
1807
1808static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001809xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001810{
1811 int i;
1812 xmlXPathObjectPtr obj;
1813
1814 if (list == NULL)
1815 return;
1816
1817 for (i = 0; i < list->number; i++) {
1818 obj = list->items[i];
1819 /*
1820 * Note that it is already assured that we don't need to
1821 * look out for namespace nodes in the node-set.
1822 */
1823 if (obj->nodesetval != NULL) {
1824 if (obj->nodesetval->nodeTab != NULL)
1825 xmlFree(obj->nodesetval->nodeTab);
1826 xmlFree(obj->nodesetval);
1827 }
1828 xmlFree(obj);
1829#ifdef XP_DEBUG_OBJ_USAGE
1830 xmlXPathDebugObjCounterAll--;
1831#endif
1832 }
1833 xmlPointerListFree(list);
1834}
1835
1836static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001837xmlXPathFreeCache(xmlXPathContextCachePtr cache)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001838{
1839 if (cache == NULL)
1840 return;
1841 if (cache->nodesetObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001842 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001843 if (cache->stringObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001844 xmlXPathCacheFreeObjectList(cache->stringObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001845 if (cache->booleanObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001846 xmlXPathCacheFreeObjectList(cache->booleanObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001847 if (cache->numberObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001848 xmlXPathCacheFreeObjectList(cache->numberObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001849 if (cache->miscObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001850 xmlXPathCacheFreeObjectList(cache->miscObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001851 xmlFree(cache);
1852}
1853
1854/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001855 * xmlXPathContextSetCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001856 *
1857 * @ctxt: the XPath context
1858 * @active: enables/disables (creates/frees) the cache
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001859 * @value: a value with semantics dependant on @options
1860 * @options: options (currently only the value 0 is used)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001861 *
1862 * Creates/frees an object cache on the XPath context.
1863 * If activates XPath objects (xmlXPathObject) will be cached internally
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001864 * to be reused.
1865 * @options:
1866 * 0: This will set the XPath object caching:
1867 * @value:
1868 * This will set the maximum number of XPath objects
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001869 * to be cached per slot
1870 * There are 5 slots for: node-set, string, number, boolean, and
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001871 * misc objects. Use <0 for the default number (100).
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001872 * Other values for @options have currently no effect.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001873 *
1874 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1875 */
1876int
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001877xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1878 int active,
1879 int value,
1880 int options)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001881{
1882 if (ctxt == NULL)
1883 return(-1);
1884 if (active) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001885 xmlXPathContextCachePtr cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001886
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001887 if (ctxt->cache == NULL) {
1888 ctxt->cache = xmlXPathNewCache();
1889 if (ctxt->cache == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001890 return(-1);
1891 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001892 cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001893 if (options == 0) {
1894 if (value < 0)
1895 value = 100;
1896 cache->maxNodeset = value;
1897 cache->maxString = value;
1898 cache->maxNumber = value;
1899 cache->maxBoolean = value;
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001900 cache->maxMisc = value;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001901 }
1902 } else if (ctxt->cache != NULL) {
1903 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1904 ctxt->cache = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001905 }
1906 return(0);
1907}
1908
1909/**
1910 * xmlXPathCacheWrapNodeSet:
1911 * @ctxt: the XPath context
1912 * @val: the NodePtr value
1913 *
1914 * This is the cached version of xmlXPathWrapNodeSet().
1915 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1916 *
1917 * Returns the created or reused object.
1918 */
1919static xmlXPathObjectPtr
1920xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
1921{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001922 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1923 xmlXPathContextCachePtr cache =
1924 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001925
1926 if ((cache->miscObjs != NULL) &&
1927 (cache->miscObjs->number != 0))
1928 {
1929 xmlXPathObjectPtr ret;
1930
1931 ret = (xmlXPathObjectPtr)
1932 cache->miscObjs->items[--cache->miscObjs->number];
1933 ret->type = XPATH_NODESET;
1934 ret->nodesetval = val;
1935#ifdef XP_DEBUG_OBJ_USAGE
1936 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
1937#endif
1938 return(ret);
1939 }
1940 }
1941
1942 return(xmlXPathWrapNodeSet(val));
1943
1944}
1945
1946/**
1947 * xmlXPathCacheWrapString:
1948 * @ctxt: the XPath context
1949 * @val: the xmlChar * value
1950 *
1951 * This is the cached version of xmlXPathWrapString().
1952 * Wraps the @val string into an XPath object.
1953 *
1954 * Returns the created or reused object.
1955 */
1956static xmlXPathObjectPtr
1957xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
1958{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001959 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1960 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001961
1962 if ((cache->stringObjs != NULL) &&
1963 (cache->stringObjs->number != 0))
1964 {
1965
1966 xmlXPathObjectPtr ret;
1967
1968 ret = (xmlXPathObjectPtr)
1969 cache->stringObjs->items[--cache->stringObjs->number];
1970 ret->type = XPATH_STRING;
1971 ret->stringval = val;
1972#ifdef XP_DEBUG_OBJ_USAGE
1973 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1974#endif
1975 return(ret);
1976 } else if ((cache->miscObjs != NULL) &&
1977 (cache->miscObjs->number != 0))
1978 {
1979 xmlXPathObjectPtr ret;
1980 /*
1981 * Fallback to misc-cache.
1982 */
1983 ret = (xmlXPathObjectPtr)
1984 cache->miscObjs->items[--cache->miscObjs->number];
1985
1986 ret->type = XPATH_STRING;
1987 ret->stringval = val;
1988#ifdef XP_DEBUG_OBJ_USAGE
1989 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1990#endif
1991 return(ret);
1992 }
1993 }
1994 return(xmlXPathWrapString(val));
1995}
1996
1997/**
1998 * xmlXPathCacheNewNodeSet:
1999 * @ctxt: the XPath context
2000 * @val: the NodePtr value
2001 *
2002 * This is the cached version of xmlXPathNewNodeSet().
2003 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2004 * it with the single Node @val
2005 *
2006 * Returns the created or reused object.
2007 */
2008static xmlXPathObjectPtr
2009xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2010{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002011 if ((ctxt != NULL) && (ctxt->cache)) {
2012 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002013
2014 if ((cache->nodesetObjs != NULL) &&
2015 (cache->nodesetObjs->number != 0))
2016 {
2017 xmlXPathObjectPtr ret;
2018 /*
2019 * Use the nodset-cache.
2020 */
2021 ret = (xmlXPathObjectPtr)
2022 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2023 ret->type = XPATH_NODESET;
2024 ret->boolval = 0;
2025 if (val) {
2026 if ((ret->nodesetval->nodeMax == 0) ||
2027 (val->type == XML_NAMESPACE_DECL))
2028 {
2029 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2030 } else {
2031 ret->nodesetval->nodeTab[0] = val;
2032 ret->nodesetval->nodeNr = 1;
2033 }
2034 }
2035#ifdef XP_DEBUG_OBJ_USAGE
2036 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2037#endif
2038 return(ret);
2039 } else if ((cache->miscObjs != NULL) &&
2040 (cache->miscObjs->number != 0))
2041 {
2042 xmlXPathObjectPtr ret;
2043 /*
2044 * Fallback to misc-cache.
2045 */
2046
2047 ret = (xmlXPathObjectPtr)
2048 cache->miscObjs->items[--cache->miscObjs->number];
2049
2050 ret->type = XPATH_NODESET;
2051 ret->boolval = 0;
2052 ret->nodesetval = xmlXPathNodeSetCreate(val);
2053#ifdef XP_DEBUG_OBJ_USAGE
2054 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2055#endif
2056 return(ret);
2057 }
2058 }
2059 return(xmlXPathNewNodeSet(val));
2060}
2061
2062/**
2063 * xmlXPathCacheNewCString:
2064 * @ctxt: the XPath context
2065 * @val: the char * value
2066 *
2067 * This is the cached version of xmlXPathNewCString().
2068 * Acquire an xmlXPathObjectPtr of type string and of value @val
2069 *
2070 * Returns the created or reused object.
2071 */
2072static xmlXPathObjectPtr
2073xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2074{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002075 if ((ctxt != NULL) && (ctxt->cache)) {
2076 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002077
2078 if ((cache->stringObjs != NULL) &&
2079 (cache->stringObjs->number != 0))
2080 {
2081 xmlXPathObjectPtr ret;
2082
2083 ret = (xmlXPathObjectPtr)
2084 cache->stringObjs->items[--cache->stringObjs->number];
2085
2086 ret->type = XPATH_STRING;
2087 ret->stringval = xmlStrdup(BAD_CAST val);
2088#ifdef XP_DEBUG_OBJ_USAGE
2089 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2090#endif
2091 return(ret);
2092 } else if ((cache->miscObjs != NULL) &&
2093 (cache->miscObjs->number != 0))
2094 {
2095 xmlXPathObjectPtr ret;
2096
2097 ret = (xmlXPathObjectPtr)
2098 cache->miscObjs->items[--cache->miscObjs->number];
2099
2100 ret->type = XPATH_STRING;
2101 ret->stringval = xmlStrdup(BAD_CAST val);
2102#ifdef XP_DEBUG_OBJ_USAGE
2103 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2104#endif
2105 return(ret);
2106 }
2107 }
2108 return(xmlXPathNewCString(val));
2109}
2110
2111/**
2112 * xmlXPathCacheNewString:
2113 * @ctxt: the XPath context
2114 * @val: the xmlChar * value
2115 *
2116 * This is the cached version of xmlXPathNewString().
2117 * Acquire an xmlXPathObjectPtr of type string and of value @val
2118 *
2119 * Returns the created or reused object.
2120 */
2121static xmlXPathObjectPtr
2122xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2123{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002124 if ((ctxt != NULL) && (ctxt->cache)) {
2125 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002126
2127 if ((cache->stringObjs != NULL) &&
2128 (cache->stringObjs->number != 0))
2129 {
2130 xmlXPathObjectPtr ret;
2131
2132 ret = (xmlXPathObjectPtr)
2133 cache->stringObjs->items[--cache->stringObjs->number];
2134 ret->type = XPATH_STRING;
2135 if (val != NULL)
2136 ret->stringval = xmlStrdup(val);
2137 else
2138 ret->stringval = xmlStrdup((const xmlChar *)"");
2139#ifdef XP_DEBUG_OBJ_USAGE
2140 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2141#endif
2142 return(ret);
2143 } else if ((cache->miscObjs != NULL) &&
2144 (cache->miscObjs->number != 0))
2145 {
2146 xmlXPathObjectPtr ret;
2147
2148 ret = (xmlXPathObjectPtr)
2149 cache->miscObjs->items[--cache->miscObjs->number];
2150
2151 ret->type = XPATH_STRING;
2152 if (val != NULL)
2153 ret->stringval = xmlStrdup(val);
2154 else
2155 ret->stringval = xmlStrdup((const xmlChar *)"");
2156#ifdef XP_DEBUG_OBJ_USAGE
2157 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2158#endif
2159 return(ret);
2160 }
2161 }
2162 return(xmlXPathNewString(val));
2163}
2164
2165/**
2166 * xmlXPathCacheNewBoolean:
2167 * @ctxt: the XPath context
2168 * @val: the boolean value
2169 *
2170 * This is the cached version of xmlXPathNewBoolean().
2171 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2172 *
2173 * Returns the created or reused object.
2174 */
2175static xmlXPathObjectPtr
2176xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2177{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002178 if ((ctxt != NULL) && (ctxt->cache)) {
2179 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002180
2181 if ((cache->booleanObjs != NULL) &&
2182 (cache->booleanObjs->number != 0))
2183 {
2184 xmlXPathObjectPtr ret;
2185
2186 ret = (xmlXPathObjectPtr)
2187 cache->booleanObjs->items[--cache->booleanObjs->number];
2188 ret->type = XPATH_BOOLEAN;
2189 ret->boolval = (val != 0);
2190#ifdef XP_DEBUG_OBJ_USAGE
2191 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2192#endif
2193 return(ret);
2194 } else if ((cache->miscObjs != NULL) &&
2195 (cache->miscObjs->number != 0))
2196 {
2197 xmlXPathObjectPtr ret;
2198
2199 ret = (xmlXPathObjectPtr)
2200 cache->miscObjs->items[--cache->miscObjs->number];
2201
2202 ret->type = XPATH_BOOLEAN;
2203 ret->boolval = (val != 0);
2204#ifdef XP_DEBUG_OBJ_USAGE
2205 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2206#endif
2207 return(ret);
2208 }
2209 }
2210 return(xmlXPathNewBoolean(val));
2211}
2212
2213/**
2214 * xmlXPathCacheNewFloat:
2215 * @ctxt: the XPath context
2216 * @val: the double value
2217 *
2218 * This is the cached version of xmlXPathNewFloat().
2219 * Acquires an xmlXPathObjectPtr of type double and of value @val
2220 *
2221 * Returns the created or reused object.
2222 */
2223static xmlXPathObjectPtr
2224xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2225{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002226 if ((ctxt != NULL) && (ctxt->cache)) {
2227 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002228
2229 if ((cache->numberObjs != NULL) &&
2230 (cache->numberObjs->number != 0))
2231 {
2232 xmlXPathObjectPtr ret;
2233
2234 ret = (xmlXPathObjectPtr)
2235 cache->numberObjs->items[--cache->numberObjs->number];
2236 ret->type = XPATH_NUMBER;
2237 ret->floatval = val;
2238#ifdef XP_DEBUG_OBJ_USAGE
2239 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2240#endif
2241 return(ret);
2242 } else if ((cache->miscObjs != NULL) &&
2243 (cache->miscObjs->number != 0))
2244 {
2245 xmlXPathObjectPtr ret;
2246
2247 ret = (xmlXPathObjectPtr)
2248 cache->miscObjs->items[--cache->miscObjs->number];
2249
2250 ret->type = XPATH_NUMBER;
2251 ret->floatval = val;
2252#ifdef XP_DEBUG_OBJ_USAGE
2253 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2254#endif
2255 return(ret);
2256 }
2257 }
2258 return(xmlXPathNewFloat(val));
2259}
2260
2261/**
2262 * xmlXPathCacheConvertString:
2263 * @ctxt: the XPath context
2264 * @val: an XPath object
2265 *
2266 * This is the cached version of xmlXPathConvertString().
2267 * Converts an existing object to its string() equivalent
2268 *
2269 * Returns a created or reused object, the old one is freed (cached)
2270 * (or the operation is done directly on @val)
2271 */
2272
2273static xmlXPathObjectPtr
2274xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2275 xmlChar *res = NULL;
2276
2277 if (val == NULL)
2278 return(xmlXPathCacheNewCString(ctxt, ""));
2279
2280 switch (val->type) {
2281 case XPATH_UNDEFINED:
2282#ifdef DEBUG_EXPR
2283 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2284#endif
2285 break;
2286 case XPATH_NODESET:
2287 case XPATH_XSLT_TREE:
2288 res = xmlXPathCastNodeSetToString(val->nodesetval);
2289 break;
2290 case XPATH_STRING:
2291 return(val);
2292 case XPATH_BOOLEAN:
2293 res = xmlXPathCastBooleanToString(val->boolval);
2294 break;
2295 case XPATH_NUMBER:
2296 res = xmlXPathCastNumberToString(val->floatval);
2297 break;
2298 case XPATH_USERS:
2299 case XPATH_POINT:
2300 case XPATH_RANGE:
2301 case XPATH_LOCATIONSET:
2302 TODO;
2303 break;
2304 }
2305 xmlXPathReleaseObject(ctxt, val);
2306 if (res == NULL)
2307 return(xmlXPathCacheNewCString(ctxt, ""));
2308 return(xmlXPathCacheWrapString(ctxt, res));
2309}
2310
2311/**
2312 * xmlXPathCacheObjectCopy:
2313 * @ctxt: the XPath context
2314 * @val: the original object
2315 *
2316 * This is the cached version of xmlXPathObjectCopy().
2317 * Acquire a copy of a given object
2318 *
2319 * Returns a created or reused created object.
2320 */
2321static xmlXPathObjectPtr
2322xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2323{
2324 if (val == NULL)
2325 return(NULL);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002326
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002327 if (XP_HAS_CACHE(ctxt)) {
2328 switch (val->type) {
2329 case XPATH_NODESET:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002330 return(xmlXPathCacheWrapNodeSet(ctxt,
2331 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002332 case XPATH_STRING:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002333 return(xmlXPathCacheNewString(ctxt, val->stringval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002334 case XPATH_BOOLEAN:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002335 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002336 case XPATH_NUMBER:
2337 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2338 default:
2339 break;
2340 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002341 }
2342 return(xmlXPathObjectCopy(val));
2343}
2344
2345/**
2346 * xmlXPathCacheConvertBoolean:
2347 * @ctxt: the XPath context
2348 * @val: an XPath object
2349 *
2350 * This is the cached version of xmlXPathConvertBoolean().
2351 * Converts an existing object to its boolean() equivalent
2352 *
2353 * Returns a created or reused object, the old one is freed (or the operation
2354 * is done directly on @val)
2355 */
2356static xmlXPathObjectPtr
2357xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2358 xmlXPathObjectPtr ret;
2359
2360 if (val == NULL)
2361 return(xmlXPathCacheNewBoolean(ctxt, 0));
2362 if (val->type == XPATH_BOOLEAN)
2363 return(val);
2364 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2365 xmlXPathReleaseObject(ctxt, val);
2366 return(ret);
2367}
2368
2369/**
2370 * xmlXPathCacheConvertNumber:
2371 * @ctxt: the XPath context
2372 * @val: an XPath object
2373 *
2374 * This is the cached version of xmlXPathConvertNumber().
2375 * Converts an existing object to its number() equivalent
2376 *
2377 * Returns a created or reused object, the old one is freed (or the operation
2378 * is done directly on @val)
2379 */
2380static xmlXPathObjectPtr
2381xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2382 xmlXPathObjectPtr ret;
2383
2384 if (val == NULL)
2385 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2386 if (val->type == XPATH_NUMBER)
2387 return(val);
2388 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2389 xmlXPathReleaseObject(ctxt, val);
2390 return(ret);
2391}
2392
2393/************************************************************************
2394 * *
Owen Taylor3473f882001-02-23 17:55:21 +00002395 * Parser stacks related functions and macros *
2396 * *
2397 ************************************************************************/
2398
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002399/**
2400 * valuePop:
2401 * @ctxt: an XPath evaluation context
2402 *
2403 * Pops the top XPath object from the value stack
2404 *
2405 * Returns the XPath object just removed
2406 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002407xmlXPathObjectPtr
Daniel Veillard1c732d22002-11-30 11:22:59 +00002408valuePop(xmlXPathParserContextPtr ctxt)
2409{
2410 xmlXPathObjectPtr ret;
2411
Daniel Veillarda82b1822004-11-08 16:24:57 +00002412 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
Daniel Veillard24505b02005-07-28 23:49:35 +00002413 return (NULL);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002414 ctxt->valueNr--;
2415 if (ctxt->valueNr > 0)
2416 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2417 else
2418 ctxt->value = NULL;
2419 ret = ctxt->valueTab[ctxt->valueNr];
Daniel Veillard24505b02005-07-28 23:49:35 +00002420 ctxt->valueTab[ctxt->valueNr] = NULL;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002421 return (ret);
2422}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002423/**
2424 * valuePush:
2425 * @ctxt: an XPath evaluation context
2426 * @value: the XPath object
2427 *
2428 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002429 *
2430 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002431 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002432int
Daniel Veillard1c732d22002-11-30 11:22:59 +00002433valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2434{
Daniel Veillarda82b1822004-11-08 16:24:57 +00002435 if ((ctxt == NULL) || (value == NULL)) return(-1);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002436 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002437 xmlXPathObjectPtr *tmp;
2438
2439 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2440 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00002441 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002442 if (tmp == NULL) {
Daniel Veillard1c732d22002-11-30 11:22:59 +00002443 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
2444 return (0);
2445 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002446 ctxt->valueMax *= 2;
2447 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002448 }
2449 ctxt->valueTab[ctxt->valueNr] = value;
2450 ctxt->value = value;
2451 return (ctxt->valueNr++);
2452}
Owen Taylor3473f882001-02-23 17:55:21 +00002453
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002454/**
2455 * xmlXPathPopBoolean:
2456 * @ctxt: an XPath parser context
2457 *
2458 * Pops a boolean from the stack, handling conversion if needed.
2459 * Check error with #xmlXPathCheckError.
2460 *
2461 * Returns the boolean
2462 */
2463int
2464xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2465 xmlXPathObjectPtr obj;
2466 int ret;
2467
2468 obj = valuePop(ctxt);
2469 if (obj == NULL) {
2470 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2471 return(0);
2472 }
William M. Brack08171912003-12-29 02:52:11 +00002473 if (obj->type != XPATH_BOOLEAN)
2474 ret = xmlXPathCastToBoolean(obj);
2475 else
2476 ret = obj->boolval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002477 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002478 return(ret);
2479}
2480
2481/**
2482 * xmlXPathPopNumber:
2483 * @ctxt: an XPath parser context
2484 *
2485 * Pops a number from the stack, handling conversion if needed.
2486 * Check error with #xmlXPathCheckError.
2487 *
2488 * Returns the number
2489 */
2490double
2491xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2492 xmlXPathObjectPtr obj;
2493 double ret;
2494
2495 obj = valuePop(ctxt);
2496 if (obj == NULL) {
2497 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2498 return(0);
2499 }
William M. Brack08171912003-12-29 02:52:11 +00002500 if (obj->type != XPATH_NUMBER)
2501 ret = xmlXPathCastToNumber(obj);
2502 else
2503 ret = obj->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002504 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002505 return(ret);
2506}
2507
2508/**
2509 * xmlXPathPopString:
2510 * @ctxt: an XPath parser context
2511 *
2512 * Pops a string from the stack, handling conversion if needed.
2513 * Check error with #xmlXPathCheckError.
2514 *
2515 * Returns the string
2516 */
2517xmlChar *
2518xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2519 xmlXPathObjectPtr obj;
2520 xmlChar * ret;
2521
2522 obj = valuePop(ctxt);
2523 if (obj == NULL) {
2524 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2525 return(NULL);
2526 }
William M. Brack08171912003-12-29 02:52:11 +00002527 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002528 /* TODO: needs refactoring somewhere else */
2529 if (obj->stringval == ret)
2530 obj->stringval = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002531 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002532 return(ret);
2533}
2534
2535/**
2536 * xmlXPathPopNodeSet:
2537 * @ctxt: an XPath parser context
2538 *
2539 * Pops a node-set from the stack, handling conversion if needed.
2540 * Check error with #xmlXPathCheckError.
2541 *
2542 * Returns the node-set
2543 */
2544xmlNodeSetPtr
2545xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2546 xmlXPathObjectPtr obj;
2547 xmlNodeSetPtr ret;
2548
Daniel Veillardf2a36f92004-11-08 17:55:01 +00002549 if (ctxt == NULL) return(NULL);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002550 if (ctxt->value == NULL) {
2551 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2552 return(NULL);
2553 }
2554 if (!xmlXPathStackIsNodeSet(ctxt)) {
2555 xmlXPathSetTypeError(ctxt);
2556 return(NULL);
2557 }
2558 obj = valuePop(ctxt);
2559 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00002560#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00002561 /* to fix memory leak of not clearing obj->user */
2562 if (obj->boolval && obj->user != NULL)
2563 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00002564#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002565 obj->nodesetval = NULL;
2566 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002567 return(ret);
2568}
2569
2570/**
2571 * xmlXPathPopExternal:
2572 * @ctxt: an XPath parser context
2573 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002574 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002575 * Check error with #xmlXPathCheckError.
2576 *
2577 * Returns the object
2578 */
2579void *
2580xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2581 xmlXPathObjectPtr obj;
2582 void * ret;
2583
Daniel Veillarda82b1822004-11-08 16:24:57 +00002584 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002585 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2586 return(NULL);
2587 }
2588 if (ctxt->value->type != XPATH_USERS) {
2589 xmlXPathSetTypeError(ctxt);
2590 return(NULL);
2591 }
2592 obj = valuePop(ctxt);
2593 ret = obj->user;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002594 obj->user = NULL;
2595 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002596 return(ret);
2597}
2598
Owen Taylor3473f882001-02-23 17:55:21 +00002599/*
2600 * Macros for accessing the content. Those should be used only by the parser,
2601 * and not exported.
2602 *
2603 * Dirty macros, i.e. one need to make assumption on the context to use them
2604 *
2605 * CUR_PTR return the current pointer to the xmlChar to be parsed.
2606 * CUR returns the current xmlChar value, i.e. a 8 bit value
2607 * in ISO-Latin or UTF-8.
2608 * This should be used internally by the parser
2609 * only to compare to ASCII values otherwise it would break when
2610 * running with UTF-8 encoding.
2611 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
2612 * to compare on ASCII based substring.
2613 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2614 * strings within the parser.
2615 * CURRENT Returns the current char value, with the full decoding of
2616 * UTF-8 if we are using this mode. It returns an int.
2617 * NEXT Skip to the next character, this does the proper decoding
2618 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
2619 * It returns the pointer to the current xmlChar.
2620 */
2621
2622#define CUR (*ctxt->cur)
2623#define SKIP(val) ctxt->cur += (val)
2624#define NXT(val) ctxt->cur[(val)]
2625#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00002626#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2627
2628#define COPY_BUF(l,b,i,v) \
2629 if (l == 1) b[i++] = (xmlChar) v; \
2630 else i += xmlCopyChar(l,&b[i],v)
2631
2632#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00002633
2634#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00002635 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00002636
2637#define CURRENT (*ctxt->cur)
2638#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
2639
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002640
2641#ifndef DBL_DIG
2642#define DBL_DIG 16
2643#endif
2644#ifndef DBL_EPSILON
2645#define DBL_EPSILON 1E-9
2646#endif
2647
2648#define UPPER_DOUBLE 1E9
2649#define LOWER_DOUBLE 1E-5
2650
2651#define INTEGER_DIGITS DBL_DIG
2652#define FRACTION_DIGITS (DBL_DIG + 1)
2653#define EXPONENT_DIGITS (3 + 2)
2654
2655/**
2656 * xmlXPathFormatNumber:
2657 * @number: number to format
2658 * @buffer: output buffer
2659 * @buffersize: size of output buffer
2660 *
2661 * Convert the number into a string representation.
2662 */
2663static void
2664xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2665{
Daniel Veillardcda96922001-08-21 10:56:31 +00002666 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002667 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00002668 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002669 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002670 break;
2671 case -1:
2672 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002673 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002674 break;
2675 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00002676 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002677 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002678 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00002679 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002680 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002681 } else if (number == ((int) number)) {
2682 char work[30];
2683 char *ptr, *cur;
Daniel Veillardb3d14912005-09-04 20:47:39 +00002684 int value = (int) number;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002685
2686 ptr = &buffer[0];
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002687 if (value == 0) {
2688 *ptr++ = '0';
2689 } else {
Daniel Veillardb3d14912005-09-04 20:47:39 +00002690 snprintf(work, 29, "%d", value);
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002691 cur = &work[0];
Daniel Veillardb3d14912005-09-04 20:47:39 +00002692 while ((*cur) && (ptr - buffer < buffersize)) {
2693 *ptr++ = *cur++;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002694 }
2695 }
2696 if (ptr - buffer < buffersize) {
2697 *ptr = 0;
2698 } else if (buffersize > 0) {
2699 ptr--;
2700 *ptr = 0;
2701 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002702 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002703 /* 3 is sign, decimal point, and terminating zero */
2704 char work[DBL_DIG + EXPONENT_DIGITS + 3];
2705 int integer_place, fraction_place;
2706 char *ptr;
2707 char *after_fraction;
2708 double absolute_value;
2709 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002710
Bjorn Reese70a9da52001-04-21 16:57:29 +00002711 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002712
Bjorn Reese70a9da52001-04-21 16:57:29 +00002713 /*
2714 * First choose format - scientific or regular floating point.
2715 * In either case, result is in work, and after_fraction points
2716 * just past the fractional part.
2717 */
2718 if ( ((absolute_value > UPPER_DOUBLE) ||
2719 (absolute_value < LOWER_DOUBLE)) &&
2720 (absolute_value != 0.0) ) {
2721 /* Use scientific notation */
2722 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2723 fraction_place = DBL_DIG - 1;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002724 size = snprintf(work, sizeof(work),"%*.*e",
Bjorn Reese70a9da52001-04-21 16:57:29 +00002725 integer_place, fraction_place, number);
Daniel Veillard11ce4002006-03-10 00:36:23 +00002726 while ((size > 0) && (work[size] != 'e')) size--;
2727 after_fraction = work + size;
2728
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002729 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002730 else {
2731 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00002732 if (absolute_value > 0.0)
2733 integer_place = 1 + (int)log10(absolute_value);
2734 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00002735 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002736 fraction_place = (integer_place > 0)
2737 ? DBL_DIG - integer_place
2738 : DBL_DIG;
2739 size = snprintf(work, sizeof(work), "%0.*f",
2740 fraction_place, number);
2741 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002742 }
2743
Bjorn Reese70a9da52001-04-21 16:57:29 +00002744 /* Remove fractional trailing zeroes */
2745 ptr = after_fraction;
2746 while (*(--ptr) == '0')
2747 ;
2748 if (*ptr != '.')
2749 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002750 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002751
2752 /* Finally copy result back to caller */
2753 size = strlen(work) + 1;
2754 if (size > buffersize) {
2755 work[buffersize - 1] = 0;
2756 size = buffersize;
2757 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002758 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002759 }
2760 break;
2761 }
2762}
2763
Owen Taylor3473f882001-02-23 17:55:21 +00002764
2765/************************************************************************
2766 * *
2767 * Routines to handle NodeSets *
2768 * *
2769 ************************************************************************/
2770
2771/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002772 * xmlXPathOrderDocElems:
2773 * @doc: an input document
2774 *
2775 * Call this routine to speed up XPath computation on static documents.
2776 * This stamps all the element nodes with the document order
2777 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00002778 * field, the value stored is actually - the node number (starting at -1)
2779 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002780 *
William M. Brack08171912003-12-29 02:52:11 +00002781 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002782 * of error.
2783 */
2784long
2785xmlXPathOrderDocElems(xmlDocPtr doc) {
2786 long count = 0;
2787 xmlNodePtr cur;
2788
2789 if (doc == NULL)
2790 return(-1);
2791 cur = doc->children;
2792 while (cur != NULL) {
2793 if (cur->type == XML_ELEMENT_NODE) {
2794 cur->content = (void *) (-(++count));
2795 if (cur->children != NULL) {
2796 cur = cur->children;
2797 continue;
2798 }
2799 }
2800 if (cur->next != NULL) {
2801 cur = cur->next;
2802 continue;
2803 }
2804 do {
2805 cur = cur->parent;
2806 if (cur == NULL)
2807 break;
2808 if (cur == (xmlNodePtr) doc) {
2809 cur = NULL;
2810 break;
2811 }
2812 if (cur->next != NULL) {
2813 cur = cur->next;
2814 break;
2815 }
2816 } while (cur != NULL);
2817 }
2818 return(count);
2819}
2820
2821/**
Owen Taylor3473f882001-02-23 17:55:21 +00002822 * xmlXPathCmpNodes:
2823 * @node1: the first node
2824 * @node2: the second node
2825 *
2826 * Compare two nodes w.r.t document order
2827 *
2828 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00002829 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00002830 */
2831int
2832xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2833 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002834 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002835 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002836 xmlNodePtr cur, root;
2837
2838 if ((node1 == NULL) || (node2 == NULL))
2839 return(-2);
2840 /*
2841 * a couple of optimizations which will avoid computations in most cases
2842 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00002843 if (node1->type == XML_ATTRIBUTE_NODE) {
2844 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002845 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002846 node1 = node1->parent;
2847 }
2848 if (node2->type == XML_ATTRIBUTE_NODE) {
2849 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002850 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002851 node2 = node2->parent;
2852 }
2853 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00002854 if (attr1 == attr2) {
2855 /* not required, but we keep attributes in order */
2856 if (attr1 != 0) {
2857 cur = attrNode2->prev;
2858 while (cur != NULL) {
2859 if (cur == attrNode1)
2860 return (1);
2861 cur = cur->prev;
2862 }
2863 return (-1);
2864 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00002865 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00002866 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00002867 if (attr2 == 1)
2868 return(1);
2869 return(-1);
2870 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002871 if ((node1->type == XML_NAMESPACE_DECL) ||
2872 (node2->type == XML_NAMESPACE_DECL))
2873 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00002874 if (node1 == node2->prev)
2875 return(1);
2876 if (node1 == node2->next)
2877 return(-1);
2878
2879 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002880 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002881 */
2882 if ((node1->type == XML_ELEMENT_NODE) &&
2883 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002884 (0 > (long) node1->content) &&
2885 (0 > (long) node2->content) &&
2886 (node1->doc == node2->doc)) {
2887 long l1, l2;
2888
2889 l1 = -((long) node1->content);
2890 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002891 if (l1 < l2)
2892 return(1);
2893 if (l1 > l2)
2894 return(-1);
2895 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002896
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002897 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002898 * compute depth to root
2899 */
2900 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2901 if (cur == node1)
2902 return(1);
2903 depth2++;
2904 }
2905 root = cur;
2906 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2907 if (cur == node2)
2908 return(-1);
2909 depth1++;
2910 }
2911 /*
2912 * Distinct document (or distinct entities :-( ) case.
2913 */
2914 if (root != cur) {
2915 return(-2);
2916 }
2917 /*
2918 * get the nearest common ancestor.
2919 */
2920 while (depth1 > depth2) {
2921 depth1--;
2922 node1 = node1->parent;
2923 }
2924 while (depth2 > depth1) {
2925 depth2--;
2926 node2 = node2->parent;
2927 }
2928 while (node1->parent != node2->parent) {
2929 node1 = node1->parent;
2930 node2 = node2->parent;
2931 /* should not happen but just in case ... */
2932 if ((node1 == NULL) || (node2 == NULL))
2933 return(-2);
2934 }
2935 /*
2936 * Find who's first.
2937 */
Daniel Veillardf49be472004-02-17 11:48:18 +00002938 if (node1 == node2->prev)
2939 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00002940 if (node1 == node2->next)
2941 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00002942 /*
2943 * Speedup using document order if availble.
2944 */
2945 if ((node1->type == XML_ELEMENT_NODE) &&
2946 (node2->type == XML_ELEMENT_NODE) &&
2947 (0 > (long) node1->content) &&
2948 (0 > (long) node2->content) &&
2949 (node1->doc == node2->doc)) {
2950 long l1, l2;
2951
2952 l1 = -((long) node1->content);
2953 l2 = -((long) node2->content);
2954 if (l1 < l2)
2955 return(1);
2956 if (l1 > l2)
2957 return(-1);
2958 }
2959
Owen Taylor3473f882001-02-23 17:55:21 +00002960 for (cur = node1->next;cur != NULL;cur = cur->next)
2961 if (cur == node2)
2962 return(1);
2963 return(-1); /* assume there is no sibling list corruption */
2964}
2965
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00002966#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002967/**
2968 * xmlXPathCmpNodesExt:
2969 * @node1: the first node
2970 * @node2: the second node
2971 *
2972 * Compare two nodes w.r.t document order.
2973 * This one is optimized for handling of non-element nodes.
2974 *
2975 * Returns -2 in case of error 1 if first point < second point, 0 if
2976 * it's the same node, -1 otherwise
2977 */
2978static int
2979xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
2980 int depth1, depth2;
2981 int misc = 0, precedence1 = 0, precedence2 = 0;
2982 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
2983 xmlNodePtr cur, root;
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00002984 long l1, l2;
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002985
2986 if ((node1 == NULL) || (node2 == NULL))
2987 return(-2);
2988
2989 if (node1 == node2)
2990 return(0);
2991
2992 /*
2993 * a couple of optimizations which will avoid computations in most cases
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00002994 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002995 switch (node1->type) {
2996 case XML_ELEMENT_NODE:
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00002997 if (node2->type == XML_ELEMENT_NODE) {
2998 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
2999 (0 > (long) node2->content) &&
3000 (node1->doc == node2->doc))
3001 {
3002 l1 = -((long) node1->content);
3003 l2 = -((long) node2->content);
3004 if (l1 < l2)
3005 return(1);
3006 if (l1 > l2)
3007 return(-1);
3008 } else
3009 goto turtle_comparison;
3010 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003011 break;
3012 case XML_ATTRIBUTE_NODE:
3013 precedence1 = 1; /* element is owner */
3014 miscNode1 = node1;
3015 node1 = node1->parent;
3016 misc = 1;
3017 break;
3018 case XML_TEXT_NODE:
3019 case XML_CDATA_SECTION_NODE:
3020 case XML_COMMENT_NODE:
3021 case XML_PI_NODE: {
3022 miscNode1 = node1;
3023 /*
3024 * Find nearest element node.
3025 */
3026 if (node1->prev != NULL) {
3027 do {
3028 node1 = node1->prev;
3029 if (node1->type == XML_ELEMENT_NODE) {
3030 precedence1 = 3; /* element in prev-sibl axis */
3031 break;
3032 }
3033 if (node1->prev == NULL) {
3034 precedence1 = 2; /* element is parent */
3035 /*
3036 * URGENT TODO: Are there any cases, where the
3037 * parent of such a node is not an element node?
3038 */
3039 node1 = node1->parent;
3040 break;
3041 }
3042 } while (1);
3043 } else {
3044 precedence1 = 2; /* element is parent */
3045 node1 = node1->parent;
3046 }
3047 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE)) {
3048 /*
3049 * Fallback for whatever case.
3050 */
3051 node1 = miscNode1;
3052 precedence1 = 0;
3053 } else
3054 misc = 1;
3055 }
3056 break;
3057 case XML_NAMESPACE_DECL:
3058 /*
3059 * TODO: why do we return 1 for namespace nodes?
3060 */
3061 return(1);
3062 default:
3063 break;
3064 }
3065 switch (node2->type) {
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003066 case XML_ELEMENT_NODE:
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003067 break;
3068 case XML_ATTRIBUTE_NODE:
3069 precedence2 = 1; /* element is owner */
3070 miscNode2 = node2;
3071 node2 = node2->parent;
3072 misc = 1;
3073 break;
3074 case XML_TEXT_NODE:
3075 case XML_CDATA_SECTION_NODE:
3076 case XML_COMMENT_NODE:
3077 case XML_PI_NODE: {
3078 miscNode2 = node2;
3079 if (node2->prev != NULL) {
3080 do {
3081 node2 = node2->prev;
3082 if (node2->type == XML_ELEMENT_NODE) {
3083 precedence2 = 3; /* element in prev-sibl axis */
3084 break;
3085 }
3086 if (node2->prev == NULL) {
3087 precedence2 = 2; /* element is parent */
3088 node2 = node2->parent;
3089 break;
3090 }
3091 } while (1);
3092 } else {
3093 precedence2 = 2; /* element is parent */
3094 node2 = node2->parent;
3095 }
3096 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3097 (0 <= (long) node1->content))
3098 {
3099 node2 = miscNode2;
3100 precedence2 = 0;
3101 } else
3102 misc = 1;
3103 }
3104 break;
3105 case XML_NAMESPACE_DECL:
3106 return(1);
3107 default:
3108 break;
3109 }
3110 if (misc) {
3111 if (node1 == node2) {
3112 if (precedence1 == precedence2) {
3113 /*
3114 * The ugly case; but normally there aren't many
3115 * adjacent non-element nodes around.
3116 */
3117 cur = miscNode2->prev;
3118 while (cur != NULL) {
3119 if (cur == miscNode1)
3120 return(1);
3121 if (cur->type == XML_ELEMENT_NODE)
3122 return(-1);
3123 cur = cur->prev;
3124 }
3125 return (-1);
3126 } else {
3127 /*
3128 * Evaluate based on higher precedence wrt to the element.
3129 * TODO: This assumes attributes are sorted before content.
3130 * Is this 100% correct?
3131 */
3132 if (precedence1 < precedence2)
3133 return(1);
3134 else
3135 return(-1);
3136 }
3137 }
3138 /*
3139 * Special case: One of the helper-elements is contained by the other.
3140 * <foo>
3141 * <node2>
3142 * <node1>Text-1(precedence1 == 2)</node1>
3143 * </node2>
3144 * Text-6(precedence2 == 3)
3145 * </foo>
3146 */
3147 if ((precedence2 == 3) && (precedence1 > 1)) {
3148 cur = node1->parent;
3149 while (cur) {
3150 if (cur == node2)
3151 return(1);
3152 cur = cur->parent;
3153 }
3154 }
3155 if ((precedence1 == 3) && (precedence2 > 1)) {
3156 cur = node2->parent;
3157 while (cur) {
3158 if (cur == node1)
3159 return(-1);
3160 cur = cur->parent;
3161 }
3162 }
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003163 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003164
3165 /*
3166 * Speedup using document order if availble.
3167 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003168 if ((node1->type == XML_ELEMENT_NODE) &&
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003169 (node2->type == XML_ELEMENT_NODE) &&
3170 (0 > (long) node1->content) &&
3171 (0 > (long) node2->content) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003172 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003173
3174 l1 = -((long) node1->content);
3175 l2 = -((long) node2->content);
3176 if (l1 < l2)
3177 return(1);
3178 if (l1 > l2)
3179 return(-1);
3180 }
3181
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003182turtle_comparison:
3183
3184 if (node1 == node2->prev)
3185 return(1);
3186 if (node1 == node2->next)
3187 return(-1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003188 /*
3189 * compute depth to root
3190 */
3191 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3192 if (cur == node1)
3193 return(1);
3194 depth2++;
3195 }
3196 root = cur;
3197 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3198 if (cur == node2)
3199 return(-1);
3200 depth1++;
3201 }
3202 /*
3203 * Distinct document (or distinct entities :-( ) case.
3204 */
3205 if (root != cur) {
3206 return(-2);
3207 }
3208 /*
3209 * get the nearest common ancestor.
3210 */
3211 while (depth1 > depth2) {
3212 depth1--;
3213 node1 = node1->parent;
3214 }
3215 while (depth2 > depth1) {
3216 depth2--;
3217 node2 = node2->parent;
3218 }
3219 while (node1->parent != node2->parent) {
3220 node1 = node1->parent;
3221 node2 = node2->parent;
3222 /* should not happen but just in case ... */
3223 if ((node1 == NULL) || (node2 == NULL))
3224 return(-2);
3225 }
3226 /*
3227 * Find who's first.
3228 */
3229 if (node1 == node2->prev)
3230 return(1);
3231 if (node1 == node2->next)
3232 return(-1);
3233 /*
3234 * Speedup using document order if availble.
3235 */
3236 if ((node1->type == XML_ELEMENT_NODE) &&
3237 (node2->type == XML_ELEMENT_NODE) &&
3238 (0 > (long) node1->content) &&
3239 (0 > (long) node2->content) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003240 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003241
3242 l1 = -((long) node1->content);
3243 l2 = -((long) node2->content);
3244 if (l1 < l2)
3245 return(1);
3246 if (l1 > l2)
3247 return(-1);
3248 }
3249
3250 for (cur = node1->next;cur != NULL;cur = cur->next)
3251 if (cur == node2)
3252 return(1);
3253 return(-1); /* assume there is no sibling list corruption */
3254}
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003255#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003256
Owen Taylor3473f882001-02-23 17:55:21 +00003257/**
3258 * xmlXPathNodeSetSort:
3259 * @set: the node set
3260 *
3261 * Sort the node set in document order
3262 */
3263void
3264xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003265 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003266 xmlNodePtr tmp;
3267
3268 if (set == NULL)
3269 return;
3270
3271 /* Use Shell's sort to sort the node-set */
3272 len = set->nodeNr;
3273 for (incr = len / 2; incr > 0; incr /= 2) {
3274 for (i = incr; i < len; i++) {
3275 j = i - incr;
3276 while (j >= 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003277#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003278 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3279 set->nodeTab[j + incr]) == -1)
3280#else
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003281 if (xmlXPathCmpNodes(set->nodeTab[j],
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003282 set->nodeTab[j + incr]) == -1)
3283#endif
3284 {
Owen Taylor3473f882001-02-23 17:55:21 +00003285 tmp = set->nodeTab[j];
3286 set->nodeTab[j] = set->nodeTab[j + incr];
3287 set->nodeTab[j + incr] = tmp;
3288 j -= incr;
3289 } else
3290 break;
3291 }
3292 }
3293 }
3294}
3295
3296#define XML_NODESET_DEFAULT 10
3297/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003298 * xmlXPathNodeSetDupNs:
3299 * @node: the parent node of the namespace XPath node
3300 * @ns: the libxml namespace declaration node.
3301 *
3302 * Namespace node in libxml don't match the XPath semantic. In a node set
3303 * the namespace nodes are duplicated and the next pointer is set to the
3304 * parent node in the XPath semantic.
3305 *
3306 * Returns the newly created object.
3307 */
3308static xmlNodePtr
3309xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3310 xmlNsPtr cur;
3311
3312 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3313 return(NULL);
3314 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3315 return((xmlNodePtr) ns);
3316
3317 /*
3318 * Allocate a new Namespace and fill the fields.
3319 */
3320 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3321 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003322 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003323 return(NULL);
3324 }
3325 memset(cur, 0, sizeof(xmlNs));
3326 cur->type = XML_NAMESPACE_DECL;
3327 if (ns->href != NULL)
3328 cur->href = xmlStrdup(ns->href);
3329 if (ns->prefix != NULL)
3330 cur->prefix = xmlStrdup(ns->prefix);
3331 cur->next = (xmlNsPtr) node;
3332 return((xmlNodePtr) cur);
3333}
3334
3335/**
3336 * xmlXPathNodeSetFreeNs:
3337 * @ns: the XPath namespace node found in a nodeset.
3338 *
William M. Brack08171912003-12-29 02:52:11 +00003339 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003340 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00003341 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003342 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00003343void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003344xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3345 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3346 return;
3347
3348 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3349 if (ns->href != NULL)
3350 xmlFree((xmlChar *)ns->href);
3351 if (ns->prefix != NULL)
3352 xmlFree((xmlChar *)ns->prefix);
3353 xmlFree(ns);
3354 }
3355}
3356
3357/**
Owen Taylor3473f882001-02-23 17:55:21 +00003358 * xmlXPathNodeSetCreate:
3359 * @val: an initial xmlNodePtr, or NULL
3360 *
3361 * Create a new xmlNodeSetPtr of type double and of value @val
3362 *
3363 * Returns the newly created object.
3364 */
3365xmlNodeSetPtr
3366xmlXPathNodeSetCreate(xmlNodePtr val) {
3367 xmlNodeSetPtr ret;
3368
3369 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3370 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003371 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003372 return(NULL);
3373 }
3374 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3375 if (val != NULL) {
3376 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3377 sizeof(xmlNodePtr));
3378 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003379 xmlXPathErrMemory(NULL, "creating nodeset\n");
3380 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003381 return(NULL);
3382 }
3383 memset(ret->nodeTab, 0 ,
3384 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3385 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003386 if (val->type == XML_NAMESPACE_DECL) {
3387 xmlNsPtr ns = (xmlNsPtr) val;
3388
3389 ret->nodeTab[ret->nodeNr++] =
3390 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3391 } else
3392 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003393 }
3394 return(ret);
3395}
3396
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003397/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003398 * xmlXPathNodeSetCreateSize:
3399 * @size: the initial size of the set
3400 *
3401 * Create a new xmlNodeSetPtr of type double and of value @val
3402 *
3403 * Returns the newly created object.
3404 */
3405static xmlNodeSetPtr
3406xmlXPathNodeSetCreateSize(int size) {
3407 xmlNodeSetPtr ret;
3408
3409 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3410 if (ret == NULL) {
3411 xmlXPathErrMemory(NULL, "creating nodeset\n");
3412 return(NULL);
3413 }
3414 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3415 if (size < XML_NODESET_DEFAULT)
3416 size = XML_NODESET_DEFAULT;
3417 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3418 if (ret->nodeTab == NULL) {
3419 xmlXPathErrMemory(NULL, "creating nodeset\n");
3420 xmlFree(ret);
3421 return(NULL);
3422 }
3423 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3424 ret->nodeMax = size;
3425 return(ret);
3426}
3427
3428/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003429 * xmlXPathNodeSetContains:
3430 * @cur: the node-set
3431 * @val: the node
3432 *
3433 * checks whether @cur contains @val
3434 *
3435 * Returns true (1) if @cur contains @val, false (0) otherwise
3436 */
3437int
3438xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3439 int i;
3440
Daniel Veillarda82b1822004-11-08 16:24:57 +00003441 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003442 if (val->type == XML_NAMESPACE_DECL) {
3443 for (i = 0; i < cur->nodeNr; i++) {
3444 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3445 xmlNsPtr ns1, ns2;
3446
3447 ns1 = (xmlNsPtr) val;
3448 ns2 = (xmlNsPtr) cur->nodeTab[i];
3449 if (ns1 == ns2)
3450 return(1);
3451 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3452 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3453 return(1);
3454 }
3455 }
3456 } else {
3457 for (i = 0; i < cur->nodeNr; i++) {
3458 if (cur->nodeTab[i] == val)
3459 return(1);
3460 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003461 }
3462 return(0);
3463}
3464
3465/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003466 * xmlXPathNodeSetAddNs:
3467 * @cur: the initial node set
3468 * @node: the hosting node
3469 * @ns: a the namespace node
3470 *
3471 * add a new namespace node to an existing NodeSet
3472 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00003473void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003474xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3475 int i;
3476
Daniel Veillarda82b1822004-11-08 16:24:57 +00003477
3478 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3479 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003480 (node->type != XML_ELEMENT_NODE))
3481 return;
3482
William M. Brack08171912003-12-29 02:52:11 +00003483 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003484 /*
William M. Brack08171912003-12-29 02:52:11 +00003485 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003486 */
3487 for (i = 0;i < cur->nodeNr;i++) {
3488 if ((cur->nodeTab[i] != NULL) &&
3489 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00003490 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003491 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3492 return;
3493 }
3494
3495 /*
3496 * grow the nodeTab if needed
3497 */
3498 if (cur->nodeMax == 0) {
3499 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3500 sizeof(xmlNodePtr));
3501 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003502 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003503 return;
3504 }
3505 memset(cur->nodeTab, 0 ,
3506 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3507 cur->nodeMax = XML_NODESET_DEFAULT;
3508 } else if (cur->nodeNr == cur->nodeMax) {
3509 xmlNodePtr *temp;
3510
3511 cur->nodeMax *= 2;
3512 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3513 sizeof(xmlNodePtr));
3514 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003515 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003516 return;
3517 }
3518 cur->nodeTab = temp;
3519 }
3520 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3521}
3522
3523/**
Owen Taylor3473f882001-02-23 17:55:21 +00003524 * xmlXPathNodeSetAdd:
3525 * @cur: the initial node set
3526 * @val: a new xmlNodePtr
3527 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003528 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00003529 */
3530void
3531xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3532 int i;
3533
Daniel Veillarda82b1822004-11-08 16:24:57 +00003534 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003535
Daniel Veillardef0b4502003-03-24 13:57:34 +00003536#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00003537 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3538 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00003539#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00003540
William M. Brack08171912003-12-29 02:52:11 +00003541 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003542 /*
William M. Brack08171912003-12-29 02:52:11 +00003543 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00003544 */
3545 for (i = 0;i < cur->nodeNr;i++)
3546 if (cur->nodeTab[i] == val) return;
3547
3548 /*
3549 * grow the nodeTab if needed
3550 */
3551 if (cur->nodeMax == 0) {
3552 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3553 sizeof(xmlNodePtr));
3554 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003555 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003556 return;
3557 }
3558 memset(cur->nodeTab, 0 ,
3559 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3560 cur->nodeMax = XML_NODESET_DEFAULT;
3561 } else if (cur->nodeNr == cur->nodeMax) {
3562 xmlNodePtr *temp;
3563
3564 cur->nodeMax *= 2;
3565 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3566 sizeof(xmlNodePtr));
3567 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003568 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003569 return;
3570 }
3571 cur->nodeTab = temp;
3572 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003573 if (val->type == XML_NAMESPACE_DECL) {
3574 xmlNsPtr ns = (xmlNsPtr) val;
3575
3576 cur->nodeTab[cur->nodeNr++] =
3577 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3578 } else
3579 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003580}
3581
3582/**
3583 * xmlXPathNodeSetAddUnique:
3584 * @cur: the initial node set
3585 * @val: a new xmlNodePtr
3586 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003587 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00003588 * when we are sure the node is not already in the set.
3589 */
3590void
3591xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00003592 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003593
Daniel Veillardef0b4502003-03-24 13:57:34 +00003594#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00003595 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3596 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00003597#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00003598
William M. Brack08171912003-12-29 02:52:11 +00003599 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003600 /*
3601 * grow the nodeTab if needed
3602 */
3603 if (cur->nodeMax == 0) {
3604 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3605 sizeof(xmlNodePtr));
3606 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003607 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003608 return;
3609 }
3610 memset(cur->nodeTab, 0 ,
3611 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3612 cur->nodeMax = XML_NODESET_DEFAULT;
3613 } else if (cur->nodeNr == cur->nodeMax) {
3614 xmlNodePtr *temp;
3615
3616 cur->nodeMax *= 2;
3617 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3618 sizeof(xmlNodePtr));
3619 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003620 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003621 return;
3622 }
3623 cur->nodeTab = temp;
3624 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003625 if (val->type == XML_NAMESPACE_DECL) {
3626 xmlNsPtr ns = (xmlNsPtr) val;
3627
3628 cur->nodeTab[cur->nodeNr++] =
3629 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3630 } else
3631 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003632}
3633
3634/**
3635 * xmlXPathNodeSetMerge:
3636 * @val1: the first NodeSet or NULL
3637 * @val2: the second NodeSet
3638 *
3639 * Merges two nodesets, all nodes from @val2 are added to @val1
3640 * if @val1 is NULL, a new set is created and copied from @val2
3641 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003642 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003643 */
3644xmlNodeSetPtr
3645xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003646 int i, j, initNr, skip;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003647 xmlNodePtr n1, n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003648
3649 if (val2 == NULL) return(val1);
3650 if (val1 == NULL) {
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003651 val1 = xmlXPathNodeSetCreate(NULL);
3652#if 0
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003653 /*
3654 * TODO: The optimization won't work in every case, since
3655 * those nasty namespace nodes need to be added with
3656 * xmlXPathNodeSetDupNs() to the set; thus a pure
3657 * memcpy is not possible.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00003658 * If there was a flag on the nodesetval, indicating that
3659 * some temporary nodes are in, that would be helpfull.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003660 */
3661 /*
3662 * Optimization: Create an equally sized node-set
3663 * and memcpy the content.
3664 */
3665 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3666 if (val1 == NULL)
3667 return(NULL);
3668 if (val2->nodeNr != 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003669 if (val2->nodeNr == 1)
3670 *(val1->nodeTab) = *(val2->nodeTab);
3671 else {
3672 memcpy(val1->nodeTab, val2->nodeTab,
3673 val2->nodeNr * sizeof(xmlNodePtr));
3674 }
3675 val1->nodeNr = val2->nodeNr;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003676 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003677 return(val1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003678#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003679 }
3680
William M. Brack08171912003-12-29 02:52:11 +00003681 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003682 initNr = val1->nodeNr;
3683
3684 for (i = 0;i < val2->nodeNr;i++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003685 n2 = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00003686 /*
William M. Brack08171912003-12-29 02:52:11 +00003687 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003688 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003689 skip = 0;
3690 for (j = 0; j < initNr; j++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003691 n1 = val1->nodeTab[j];
3692 if (n1 == n2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003693 skip = 1;
3694 break;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003695 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3696 (n2->type == XML_NAMESPACE_DECL)) {
3697 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3698 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3699 ((xmlNsPtr) n2)->prefix)))
3700 {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003701 skip = 1;
3702 break;
3703 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003704 }
3705 }
3706 if (skip)
3707 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00003708
3709 /*
3710 * grow the nodeTab if needed
3711 */
3712 if (val1->nodeMax == 0) {
3713 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3714 sizeof(xmlNodePtr));
3715 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003716 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003717 return(NULL);
3718 }
3719 memset(val1->nodeTab, 0 ,
3720 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3721 val1->nodeMax = XML_NODESET_DEFAULT;
3722 } else if (val1->nodeNr == val1->nodeMax) {
3723 xmlNodePtr *temp;
3724
3725 val1->nodeMax *= 2;
3726 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3727 sizeof(xmlNodePtr));
3728 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003729 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003730 return(NULL);
3731 }
3732 val1->nodeTab = temp;
3733 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003734 if (n2->type == XML_NAMESPACE_DECL) {
3735 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003736
3737 val1->nodeTab[val1->nodeNr++] =
3738 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3739 } else
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003740 val1->nodeTab[val1->nodeNr++] = n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003741 }
3742
3743 return(val1);
3744}
3745
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003746#if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
Owen Taylor3473f882001-02-23 17:55:21 +00003747/**
Daniel Veillard75be0132002-03-13 10:03:35 +00003748 * xmlXPathNodeSetMergeUnique:
3749 * @val1: the first NodeSet or NULL
3750 * @val2: the second NodeSet
3751 *
3752 * Merges two nodesets, all nodes from @val2 are added to @val1
3753 * if @val1 is NULL, a new set is created and copied from @val2
3754 *
3755 * Returns @val1 once extended or NULL in case of error.
3756 */
3757static xmlNodeSetPtr
3758xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00003759 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00003760
3761 if (val2 == NULL) return(val1);
3762 if (val1 == NULL) {
3763 val1 = xmlXPathNodeSetCreate(NULL);
3764 }
3765
William M. Brack08171912003-12-29 02:52:11 +00003766 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00003767
3768 for (i = 0;i < val2->nodeNr;i++) {
3769 /*
3770 * grow the nodeTab if needed
3771 */
3772 if (val1->nodeMax == 0) {
3773 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3774 sizeof(xmlNodePtr));
3775 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003776 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00003777 return(NULL);
3778 }
3779 memset(val1->nodeTab, 0 ,
3780 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3781 val1->nodeMax = XML_NODESET_DEFAULT;
3782 } else if (val1->nodeNr == val1->nodeMax) {
3783 xmlNodePtr *temp;
3784
3785 val1->nodeMax *= 2;
3786 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3787 sizeof(xmlNodePtr));
3788 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003789 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00003790 return(NULL);
3791 }
3792 val1->nodeTab = temp;
3793 }
3794 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3795 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
3796
3797 val1->nodeTab[val1->nodeNr++] =
3798 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3799 } else
3800 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
3801 }
3802
3803 return(val1);
3804}
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003805#endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3806
3807/**
3808 * xmlXPathNodeSetMergeAndClear:
3809 * @set1: the first NodeSet or NULL
3810 * @set2: the second NodeSet
3811 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3812 *
3813 * Merges two nodesets, all nodes from @set2 are added to @set1
3814 * if @set1 is NULL, a new set is created and copied from @set2.
3815 * Checks for duplicate nodes. Clears set2.
3816 *
3817 * Returns @set1 once extended or NULL in case of error.
3818 */
3819static xmlNodeSetPtr
3820xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3821 int hasNullEntries)
3822{
3823 if ((set1 == NULL) && (hasNullEntries == 0)) {
3824 /*
3825 * Note that doing a memcpy of the list, namespace nodes are
3826 * just assigned to set1, since set2 is cleared anyway.
3827 */
3828 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3829 if (set1 == NULL)
3830 return(NULL);
3831 if (set2->nodeNr != 0) {
3832 memcpy(set1->nodeTab, set2->nodeTab,
3833 set2->nodeNr * sizeof(xmlNodePtr));
3834 set1->nodeNr = set2->nodeNr;
3835 }
3836 } else {
3837 int i, j, initNbSet1;
3838 xmlNodePtr n1, n2;
3839
3840 if (set1 == NULL)
3841 set1 = xmlXPathNodeSetCreate(NULL);
3842
3843 initNbSet1 = set1->nodeNr;
3844 for (i = 0;i < set2->nodeNr;i++) {
3845 n2 = set2->nodeTab[i];
3846 /*
3847 * Skip NULLed entries.
3848 */
3849 if (n2 == NULL)
3850 continue;
3851 /*
3852 * Skip duplicates.
3853 */
3854 for (j = 0; j < initNbSet1; j++) {
3855 n1 = set1->nodeTab[j];
3856 if (n1 == n2) {
3857 goto skip_node;
3858 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3859 (n2->type == XML_NAMESPACE_DECL))
3860 {
3861 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3862 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3863 ((xmlNsPtr) n2)->prefix)))
3864 {
3865 /*
3866 * Free the namespace node.
3867 */
3868 set2->nodeTab[i] = NULL;
3869 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3870 goto skip_node;
3871 }
3872 }
3873 }
3874 /*
3875 * grow the nodeTab if needed
3876 */
3877 if (set1->nodeMax == 0) {
3878 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3879 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3880 if (set1->nodeTab == NULL) {
3881 xmlXPathErrMemory(NULL, "merging nodeset\n");
3882 return(NULL);
3883 }
3884 memset(set1->nodeTab, 0,
3885 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3886 set1->nodeMax = XML_NODESET_DEFAULT;
3887 } else if (set1->nodeNr >= set1->nodeMax) {
3888 xmlNodePtr *temp;
3889
3890 set1->nodeMax *= 2;
3891 temp = (xmlNodePtr *) xmlRealloc(
3892 set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3893 if (temp == NULL) {
3894 xmlXPathErrMemory(NULL, "merging nodeset\n");
3895 return(NULL);
3896 }
3897 set1->nodeTab = temp;
3898 }
3899 if (n2->type == XML_NAMESPACE_DECL) {
3900 xmlNsPtr ns = (xmlNsPtr) n2;
3901
3902 set1->nodeTab[set1->nodeNr++] =
3903 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3904 } else
3905 set1->nodeTab[set1->nodeNr++] = n2;
3906skip_node:
3907 {}
3908 }
3909 }
3910 set2->nodeNr = 0;
3911 return(set1);
3912}
3913
3914/**
3915 * xmlXPathNodeSetMergeAndClearNoDupls:
3916 * @set1: the first NodeSet or NULL
3917 * @set2: the second NodeSet
3918 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3919 *
3920 * Merges two nodesets, all nodes from @set2 are added to @set1
3921 * if @set1 is NULL, a new set is created and copied from @set2.
3922 * Doesn't chack for duplicate nodes. Clears set2.
3923 *
3924 * Returns @set1 once extended or NULL in case of error.
3925 */
3926static xmlNodeSetPtr
3927xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3928 int hasNullEntries)
3929{
3930 if (set2 == NULL)
3931 return(set1);
3932 if ((set1 == NULL) && (hasNullEntries == 0)) {
3933 /*
3934 * Note that doing a memcpy of the list, namespace nodes are
3935 * just assigned to set1, since set2 is cleared anyway.
3936 */
3937 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3938 if (set1 == NULL)
3939 return(NULL);
3940 if (set2->nodeNr != 0) {
3941 memcpy(set1->nodeTab, set2->nodeTab,
3942 set2->nodeNr * sizeof(xmlNodePtr));
3943 set1->nodeNr = set2->nodeNr;
3944 }
3945 } else {
3946 int i;
3947 xmlNodePtr n2;
3948
3949 if (set1 == NULL)
3950 set1 = xmlXPathNodeSetCreate(NULL);
3951
3952 for (i = 0;i < set2->nodeNr;i++) {
3953 n2 = set2->nodeTab[i];
3954 /*
3955 * Skip NULLed entries.
3956 */
3957 if (n2 == NULL)
3958 continue;
3959 if (set1->nodeMax == 0) {
3960 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3961 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3962 if (set1->nodeTab == NULL) {
3963 xmlXPathErrMemory(NULL, "merging nodeset\n");
3964 return(NULL);
3965 }
3966 memset(set1->nodeTab, 0,
3967 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3968 set1->nodeMax = XML_NODESET_DEFAULT;
3969 } else if (set1->nodeNr >= set1->nodeMax) {
3970 xmlNodePtr *temp;
3971
3972 set1->nodeMax *= 2;
3973 temp = (xmlNodePtr *) xmlRealloc(
3974 set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3975 if (temp == NULL) {
3976 xmlXPathErrMemory(NULL, "merging nodeset\n");
3977 return(NULL);
3978 }
3979 set1->nodeTab = temp;
3980 }
3981 set1->nodeTab[set1->nodeNr++] = n2;
3982 }
3983 }
3984 set2->nodeNr = 0;
3985 return(set1);
3986}
Daniel Veillard75be0132002-03-13 10:03:35 +00003987
3988/**
Owen Taylor3473f882001-02-23 17:55:21 +00003989 * xmlXPathNodeSetDel:
3990 * @cur: the initial node set
3991 * @val: an xmlNodePtr
3992 *
3993 * Removes an xmlNodePtr from an existing NodeSet
3994 */
3995void
3996xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
3997 int i;
3998
3999 if (cur == NULL) return;
4000 if (val == NULL) return;
4001
4002 /*
William M. Brack08171912003-12-29 02:52:11 +00004003 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00004004 */
4005 for (i = 0;i < cur->nodeNr;i++)
4006 if (cur->nodeTab[i] == val) break;
4007
William M. Brack08171912003-12-29 02:52:11 +00004008 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00004009#ifdef DEBUG
4010 xmlGenericError(xmlGenericErrorContext,
4011 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4012 val->name);
4013#endif
4014 return;
4015 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004016 if ((cur->nodeTab[i] != NULL) &&
4017 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4018 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004019 cur->nodeNr--;
4020 for (;i < cur->nodeNr;i++)
4021 cur->nodeTab[i] = cur->nodeTab[i + 1];
4022 cur->nodeTab[cur->nodeNr] = NULL;
4023}
4024
4025/**
4026 * xmlXPathNodeSetRemove:
4027 * @cur: the initial node set
4028 * @val: the index to remove
4029 *
4030 * Removes an entry from an existing NodeSet list.
4031 */
4032void
4033xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4034 if (cur == NULL) return;
4035 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004036 if ((cur->nodeTab[val] != NULL) &&
4037 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4038 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00004039 cur->nodeNr--;
4040 for (;val < cur->nodeNr;val++)
4041 cur->nodeTab[val] = cur->nodeTab[val + 1];
4042 cur->nodeTab[cur->nodeNr] = NULL;
4043}
4044
4045/**
4046 * xmlXPathFreeNodeSet:
4047 * @obj: the xmlNodeSetPtr to free
4048 *
4049 * Free the NodeSet compound (not the actual nodes !).
4050 */
4051void
4052xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4053 if (obj == NULL) return;
4054 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004055 int i;
4056
William M. Brack08171912003-12-29 02:52:11 +00004057 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004058 for (i = 0;i < obj->nodeNr;i++)
4059 if ((obj->nodeTab[i] != NULL) &&
4060 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4061 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004062 xmlFree(obj->nodeTab);
4063 }
Owen Taylor3473f882001-02-23 17:55:21 +00004064 xmlFree(obj);
4065}
4066
4067/**
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004068 * xmlXPathNodeSetClear:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004069 * @set: the node set to clear
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004070 *
4071 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4072 * are feed), but does *not* free the list itself. Sets the length of the
4073 * list to 0.
4074 */
4075static void
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004076xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4077{
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004078 if ((set == NULL) || (set->nodeNr <= 0))
4079 return;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004080 else if (hasNsNodes) {
4081 int i;
4082 xmlNodePtr node;
4083
4084 for (i = 0; i < set->nodeNr; i++) {
4085 node = set->nodeTab[i];
4086 if ((node != NULL) &&
4087 (node->type == XML_NAMESPACE_DECL))
4088 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4089 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004090 }
4091 set->nodeNr = 0;
4092}
4093
4094/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004095 * xmlXPathNodeSetClearFromPos:
4096 * @set: the node set to be cleared
4097 * @pos: the start position to clear from
4098 *
4099 * Clears the list from temporary XPath objects (e.g. namespace nodes
4100 * are feed) starting with the entry at @pos, but does *not* free the list
4101 * itself. Sets the length of the list to @pos.
4102 */
4103static void
4104xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4105{
4106 if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4107 return;
4108 else if ((hasNsNodes)) {
4109 int i;
4110 xmlNodePtr node;
4111
4112 for (i = pos; i < set->nodeNr; i++) {
4113 node = set->nodeTab[i];
4114 if ((node != NULL) &&
4115 (node->type == XML_NAMESPACE_DECL))
4116 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4117 }
4118 }
4119 set->nodeNr = pos;
4120}
4121
4122/**
Owen Taylor3473f882001-02-23 17:55:21 +00004123 * xmlXPathFreeValueTree:
4124 * @obj: the xmlNodeSetPtr to free
4125 *
4126 * Free the NodeSet compound and the actual tree, this is different
4127 * from xmlXPathFreeNodeSet()
4128 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004129static void
Owen Taylor3473f882001-02-23 17:55:21 +00004130xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4131 int i;
4132
4133 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00004134
4135 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004136 for (i = 0;i < obj->nodeNr;i++) {
4137 if (obj->nodeTab[i] != NULL) {
4138 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4139 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4140 } else {
4141 xmlFreeNodeList(obj->nodeTab[i]);
4142 }
4143 }
4144 }
Owen Taylor3473f882001-02-23 17:55:21 +00004145 xmlFree(obj->nodeTab);
4146 }
Owen Taylor3473f882001-02-23 17:55:21 +00004147 xmlFree(obj);
4148}
4149
4150#if defined(DEBUG) || defined(DEBUG_STEP)
4151/**
4152 * xmlGenericErrorContextNodeSet:
4153 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00004154 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00004155 *
4156 * Quick display of a NodeSet
4157 */
4158void
4159xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4160 int i;
4161
4162 if (output == NULL) output = xmlGenericErrorContext;
4163 if (obj == NULL) {
4164 fprintf(output, "NodeSet == NULL !\n");
4165 return;
4166 }
4167 if (obj->nodeNr == 0) {
4168 fprintf(output, "NodeSet is empty\n");
4169 return;
4170 }
4171 if (obj->nodeTab == NULL) {
4172 fprintf(output, " nodeTab == NULL !\n");
4173 return;
4174 }
4175 for (i = 0; i < obj->nodeNr; i++) {
4176 if (obj->nodeTab[i] == NULL) {
4177 fprintf(output, " NULL !\n");
4178 return;
4179 }
4180 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4181 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4182 fprintf(output, " /");
4183 else if (obj->nodeTab[i]->name == NULL)
4184 fprintf(output, " noname!");
4185 else fprintf(output, " %s", obj->nodeTab[i]->name);
4186 }
4187 fprintf(output, "\n");
4188}
4189#endif
4190
4191/**
4192 * xmlXPathNewNodeSet:
4193 * @val: the NodePtr value
4194 *
4195 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4196 * it with the single Node @val
4197 *
4198 * Returns the newly created object.
4199 */
4200xmlXPathObjectPtr
4201xmlXPathNewNodeSet(xmlNodePtr val) {
4202 xmlXPathObjectPtr ret;
4203
4204 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4205 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004206 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004207 return(NULL);
4208 }
4209 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4210 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00004211 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004212 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00004213 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004214#ifdef XP_DEBUG_OBJ_USAGE
4215 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4216#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004217 return(ret);
4218}
4219
4220/**
4221 * xmlXPathNewValueTree:
4222 * @val: the NodePtr value
4223 *
4224 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4225 * it with the tree root @val
4226 *
4227 * Returns the newly created object.
4228 */
4229xmlXPathObjectPtr
4230xmlXPathNewValueTree(xmlNodePtr val) {
4231 xmlXPathObjectPtr ret;
4232
4233 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4234 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004235 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004236 return(NULL);
4237 }
4238 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4239 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00004240 ret->boolval = 1;
4241 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00004242 ret->nodesetval = xmlXPathNodeSetCreate(val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004243#ifdef XP_DEBUG_OBJ_USAGE
4244 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4245#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004246 return(ret);
4247}
4248
4249/**
4250 * xmlXPathNewNodeSetList:
4251 * @val: an existing NodeSet
4252 *
4253 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4254 * it with the Nodeset @val
4255 *
4256 * Returns the newly created object.
4257 */
4258xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004259xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4260{
Owen Taylor3473f882001-02-23 17:55:21 +00004261 xmlXPathObjectPtr ret;
4262 int i;
4263
4264 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004265 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00004266 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004267 ret = xmlXPathNewNodeSet(NULL);
4268 else {
4269 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4270 for (i = 1; i < val->nodeNr; ++i)
4271 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
4272 }
Owen Taylor3473f882001-02-23 17:55:21 +00004273
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004274 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004275}
4276
4277/**
4278 * xmlXPathWrapNodeSet:
4279 * @val: the NodePtr value
4280 *
4281 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4282 *
4283 * Returns the newly created object.
4284 */
4285xmlXPathObjectPtr
4286xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4287 xmlXPathObjectPtr ret;
4288
4289 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4290 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004291 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004292 return(NULL);
4293 }
4294 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4295 ret->type = XPATH_NODESET;
4296 ret->nodesetval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004297#ifdef XP_DEBUG_OBJ_USAGE
4298 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4299#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004300 return(ret);
4301}
4302
4303/**
4304 * xmlXPathFreeNodeSetList:
4305 * @obj: an existing NodeSetList object
4306 *
4307 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4308 * the list contrary to xmlXPathFreeObject().
4309 */
4310void
4311xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4312 if (obj == NULL) return;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004313#ifdef XP_DEBUG_OBJ_USAGE
4314 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4315#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004316 xmlFree(obj);
4317}
4318
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004319/**
4320 * xmlXPathDifference:
4321 * @nodes1: a node-set
4322 * @nodes2: a node-set
4323 *
4324 * Implements the EXSLT - Sets difference() function:
4325 * node-set set:difference (node-set, node-set)
4326 *
4327 * Returns the difference between the two node sets, or nodes1 if
4328 * nodes2 is empty
4329 */
4330xmlNodeSetPtr
4331xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4332 xmlNodeSetPtr ret;
4333 int i, l1;
4334 xmlNodePtr cur;
4335
4336 if (xmlXPathNodeSetIsEmpty(nodes2))
4337 return(nodes1);
4338
4339 ret = xmlXPathNodeSetCreate(NULL);
4340 if (xmlXPathNodeSetIsEmpty(nodes1))
4341 return(ret);
4342
4343 l1 = xmlXPathNodeSetGetLength(nodes1);
4344
4345 for (i = 0; i < l1; i++) {
4346 cur = xmlXPathNodeSetItem(nodes1, i);
4347 if (!xmlXPathNodeSetContains(nodes2, cur))
4348 xmlXPathNodeSetAddUnique(ret, cur);
4349 }
4350 return(ret);
4351}
4352
4353/**
4354 * xmlXPathIntersection:
4355 * @nodes1: a node-set
4356 * @nodes2: a node-set
4357 *
4358 * Implements the EXSLT - Sets intersection() function:
4359 * node-set set:intersection (node-set, node-set)
4360 *
4361 * Returns a node set comprising the nodes that are within both the
4362 * node sets passed as arguments
4363 */
4364xmlNodeSetPtr
4365xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4366 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4367 int i, l1;
4368 xmlNodePtr cur;
4369
4370 if (xmlXPathNodeSetIsEmpty(nodes1))
4371 return(ret);
4372 if (xmlXPathNodeSetIsEmpty(nodes2))
4373 return(ret);
4374
4375 l1 = xmlXPathNodeSetGetLength(nodes1);
4376
4377 for (i = 0; i < l1; i++) {
4378 cur = xmlXPathNodeSetItem(nodes1, i);
4379 if (xmlXPathNodeSetContains(nodes2, cur))
4380 xmlXPathNodeSetAddUnique(ret, cur);
4381 }
4382 return(ret);
4383}
4384
4385/**
4386 * xmlXPathDistinctSorted:
4387 * @nodes: a node-set, sorted by document order
4388 *
4389 * Implements the EXSLT - Sets distinct() function:
4390 * node-set set:distinct (node-set)
4391 *
4392 * Returns a subset of the nodes contained in @nodes, or @nodes if
4393 * it is empty
4394 */
4395xmlNodeSetPtr
4396xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4397 xmlNodeSetPtr ret;
4398 xmlHashTablePtr hash;
4399 int i, l;
4400 xmlChar * strval;
4401 xmlNodePtr cur;
4402
4403 if (xmlXPathNodeSetIsEmpty(nodes))
4404 return(nodes);
4405
4406 ret = xmlXPathNodeSetCreate(NULL);
4407 l = xmlXPathNodeSetGetLength(nodes);
4408 hash = xmlHashCreate (l);
4409 for (i = 0; i < l; i++) {
4410 cur = xmlXPathNodeSetItem(nodes, i);
4411 strval = xmlXPathCastNodeToString(cur);
4412 if (xmlHashLookup(hash, strval) == NULL) {
4413 xmlHashAddEntry(hash, strval, strval);
4414 xmlXPathNodeSetAddUnique(ret, cur);
4415 } else {
4416 xmlFree(strval);
4417 }
4418 }
4419 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4420 return(ret);
4421}
4422
4423/**
4424 * xmlXPathDistinct:
4425 * @nodes: a node-set
4426 *
4427 * Implements the EXSLT - Sets distinct() function:
4428 * node-set set:distinct (node-set)
4429 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4430 * is called with the sorted node-set
4431 *
4432 * Returns a subset of the nodes contained in @nodes, or @nodes if
4433 * it is empty
4434 */
4435xmlNodeSetPtr
4436xmlXPathDistinct (xmlNodeSetPtr nodes) {
4437 if (xmlXPathNodeSetIsEmpty(nodes))
4438 return(nodes);
4439
4440 xmlXPathNodeSetSort(nodes);
4441 return(xmlXPathDistinctSorted(nodes));
4442}
4443
4444/**
4445 * xmlXPathHasSameNodes:
4446 * @nodes1: a node-set
4447 * @nodes2: a node-set
4448 *
4449 * Implements the EXSLT - Sets has-same-nodes function:
4450 * boolean set:has-same-node(node-set, node-set)
4451 *
4452 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4453 * otherwise
4454 */
4455int
4456xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4457 int i, l;
4458 xmlNodePtr cur;
4459
4460 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4461 xmlXPathNodeSetIsEmpty(nodes2))
4462 return(0);
4463
4464 l = xmlXPathNodeSetGetLength(nodes1);
4465 for (i = 0; i < l; i++) {
4466 cur = xmlXPathNodeSetItem(nodes1, i);
4467 if (xmlXPathNodeSetContains(nodes2, cur))
4468 return(1);
4469 }
4470 return(0);
4471}
4472
4473/**
4474 * xmlXPathNodeLeadingSorted:
4475 * @nodes: a node-set, sorted by document order
4476 * @node: a node
4477 *
4478 * Implements the EXSLT - Sets leading() function:
4479 * node-set set:leading (node-set, node-set)
4480 *
4481 * Returns the nodes in @nodes that precede @node in document order,
4482 * @nodes if @node is NULL or an empty node-set if @nodes
4483 * doesn't contain @node
4484 */
4485xmlNodeSetPtr
4486xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4487 int i, l;
4488 xmlNodePtr cur;
4489 xmlNodeSetPtr ret;
4490
4491 if (node == NULL)
4492 return(nodes);
4493
4494 ret = xmlXPathNodeSetCreate(NULL);
4495 if (xmlXPathNodeSetIsEmpty(nodes) ||
4496 (!xmlXPathNodeSetContains(nodes, node)))
4497 return(ret);
4498
4499 l = xmlXPathNodeSetGetLength(nodes);
4500 for (i = 0; i < l; i++) {
4501 cur = xmlXPathNodeSetItem(nodes, i);
4502 if (cur == node)
4503 break;
4504 xmlXPathNodeSetAddUnique(ret, cur);
4505 }
4506 return(ret);
4507}
4508
4509/**
4510 * xmlXPathNodeLeading:
4511 * @nodes: a node-set
4512 * @node: a node
4513 *
4514 * Implements the EXSLT - Sets leading() function:
4515 * node-set set:leading (node-set, node-set)
4516 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4517 * is called.
4518 *
4519 * Returns the nodes in @nodes that precede @node in document order,
4520 * @nodes if @node is NULL or an empty node-set if @nodes
4521 * doesn't contain @node
4522 */
4523xmlNodeSetPtr
4524xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4525 xmlXPathNodeSetSort(nodes);
4526 return(xmlXPathNodeLeadingSorted(nodes, node));
4527}
4528
4529/**
4530 * xmlXPathLeadingSorted:
4531 * @nodes1: a node-set, sorted by document order
4532 * @nodes2: a node-set, sorted by document order
4533 *
4534 * Implements the EXSLT - Sets leading() function:
4535 * node-set set:leading (node-set, node-set)
4536 *
4537 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4538 * in document order, @nodes1 if @nodes2 is NULL or empty or
4539 * an empty node-set if @nodes1 doesn't contain @nodes2
4540 */
4541xmlNodeSetPtr
4542xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4543 if (xmlXPathNodeSetIsEmpty(nodes2))
4544 return(nodes1);
4545 return(xmlXPathNodeLeadingSorted(nodes1,
4546 xmlXPathNodeSetItem(nodes2, 1)));
4547}
4548
4549/**
4550 * xmlXPathLeading:
4551 * @nodes1: a node-set
4552 * @nodes2: a node-set
4553 *
4554 * Implements the EXSLT - Sets leading() function:
4555 * node-set set:leading (node-set, node-set)
4556 * @nodes1 and @nodes2 are sorted by document order, then
4557 * #exslSetsLeadingSorted is called.
4558 *
4559 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4560 * in document order, @nodes1 if @nodes2 is NULL or empty or
4561 * an empty node-set if @nodes1 doesn't contain @nodes2
4562 */
4563xmlNodeSetPtr
4564xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4565 if (xmlXPathNodeSetIsEmpty(nodes2))
4566 return(nodes1);
4567 if (xmlXPathNodeSetIsEmpty(nodes1))
4568 return(xmlXPathNodeSetCreate(NULL));
4569 xmlXPathNodeSetSort(nodes1);
4570 xmlXPathNodeSetSort(nodes2);
4571 return(xmlXPathNodeLeadingSorted(nodes1,
4572 xmlXPathNodeSetItem(nodes2, 1)));
4573}
4574
4575/**
4576 * xmlXPathNodeTrailingSorted:
4577 * @nodes: a node-set, sorted by document order
4578 * @node: a node
4579 *
4580 * Implements the EXSLT - Sets trailing() function:
4581 * node-set set:trailing (node-set, node-set)
4582 *
4583 * Returns the nodes in @nodes that follow @node in document order,
4584 * @nodes if @node is NULL or an empty node-set if @nodes
4585 * doesn't contain @node
4586 */
4587xmlNodeSetPtr
4588xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4589 int i, l;
4590 xmlNodePtr cur;
4591 xmlNodeSetPtr ret;
4592
4593 if (node == NULL)
4594 return(nodes);
4595
4596 ret = xmlXPathNodeSetCreate(NULL);
4597 if (xmlXPathNodeSetIsEmpty(nodes) ||
4598 (!xmlXPathNodeSetContains(nodes, node)))
4599 return(ret);
4600
4601 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00004602 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004603 cur = xmlXPathNodeSetItem(nodes, i);
4604 if (cur == node)
4605 break;
4606 xmlXPathNodeSetAddUnique(ret, cur);
4607 }
4608 return(ret);
4609}
4610
4611/**
4612 * xmlXPathNodeTrailing:
4613 * @nodes: a node-set
4614 * @node: a node
4615 *
4616 * Implements the EXSLT - Sets trailing() function:
4617 * node-set set:trailing (node-set, node-set)
4618 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4619 * is called.
4620 *
4621 * Returns the nodes in @nodes that follow @node in document order,
4622 * @nodes if @node is NULL or an empty node-set if @nodes
4623 * doesn't contain @node
4624 */
4625xmlNodeSetPtr
4626xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4627 xmlXPathNodeSetSort(nodes);
4628 return(xmlXPathNodeTrailingSorted(nodes, node));
4629}
4630
4631/**
4632 * xmlXPathTrailingSorted:
4633 * @nodes1: a node-set, sorted by document order
4634 * @nodes2: a node-set, sorted by document order
4635 *
4636 * Implements the EXSLT - Sets trailing() function:
4637 * node-set set:trailing (node-set, node-set)
4638 *
4639 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4640 * in document order, @nodes1 if @nodes2 is NULL or empty or
4641 * an empty node-set if @nodes1 doesn't contain @nodes2
4642 */
4643xmlNodeSetPtr
4644xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4645 if (xmlXPathNodeSetIsEmpty(nodes2))
4646 return(nodes1);
4647 return(xmlXPathNodeTrailingSorted(nodes1,
4648 xmlXPathNodeSetItem(nodes2, 0)));
4649}
4650
4651/**
4652 * xmlXPathTrailing:
4653 * @nodes1: a node-set
4654 * @nodes2: a node-set
4655 *
4656 * Implements the EXSLT - Sets trailing() function:
4657 * node-set set:trailing (node-set, node-set)
4658 * @nodes1 and @nodes2 are sorted by document order, then
4659 * #xmlXPathTrailingSorted is called.
4660 *
4661 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4662 * in document order, @nodes1 if @nodes2 is NULL or empty or
4663 * an empty node-set if @nodes1 doesn't contain @nodes2
4664 */
4665xmlNodeSetPtr
4666xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4667 if (xmlXPathNodeSetIsEmpty(nodes2))
4668 return(nodes1);
4669 if (xmlXPathNodeSetIsEmpty(nodes1))
4670 return(xmlXPathNodeSetCreate(NULL));
4671 xmlXPathNodeSetSort(nodes1);
4672 xmlXPathNodeSetSort(nodes2);
4673 return(xmlXPathNodeTrailingSorted(nodes1,
4674 xmlXPathNodeSetItem(nodes2, 0)));
4675}
4676
Owen Taylor3473f882001-02-23 17:55:21 +00004677/************************************************************************
4678 * *
4679 * Routines to handle extra functions *
4680 * *
4681 ************************************************************************/
4682
4683/**
4684 * xmlXPathRegisterFunc:
4685 * @ctxt: the XPath context
4686 * @name: the function name
4687 * @f: the function implementation or NULL
4688 *
4689 * Register a new function. If @f is NULL it unregisters the function
4690 *
4691 * Returns 0 in case of success, -1 in case of error
4692 */
4693int
4694xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4695 xmlXPathFunction f) {
4696 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4697}
4698
4699/**
4700 * xmlXPathRegisterFuncNS:
4701 * @ctxt: the XPath context
4702 * @name: the function name
4703 * @ns_uri: the function namespace URI
4704 * @f: the function implementation or NULL
4705 *
4706 * Register a new function. If @f is NULL it unregisters the function
4707 *
4708 * Returns 0 in case of success, -1 in case of error
4709 */
4710int
4711xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4712 const xmlChar *ns_uri, xmlXPathFunction f) {
4713 if (ctxt == NULL)
4714 return(-1);
4715 if (name == NULL)
4716 return(-1);
4717
4718 if (ctxt->funcHash == NULL)
4719 ctxt->funcHash = xmlHashCreate(0);
4720 if (ctxt->funcHash == NULL)
4721 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004722 if (f == NULL)
4723 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
William M. Brackad0e67c2004-12-01 14:35:10 +00004724 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
Owen Taylor3473f882001-02-23 17:55:21 +00004725}
4726
4727/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00004728 * xmlXPathRegisterFuncLookup:
4729 * @ctxt: the XPath context
4730 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004731 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00004732 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004733 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00004734 */
4735void
4736xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4737 xmlXPathFuncLookupFunc f,
4738 void *funcCtxt) {
4739 if (ctxt == NULL)
4740 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004741 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004742 ctxt->funcLookupData = funcCtxt;
4743}
4744
4745/**
Owen Taylor3473f882001-02-23 17:55:21 +00004746 * xmlXPathFunctionLookup:
4747 * @ctxt: the XPath context
4748 * @name: the function name
4749 *
4750 * Search in the Function array of the context for the given
4751 * function.
4752 *
4753 * Returns the xmlXPathFunction or NULL if not found
4754 */
4755xmlXPathFunction
4756xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00004757 if (ctxt == NULL)
4758 return (NULL);
4759
4760 if (ctxt->funcLookupFunc != NULL) {
4761 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004762 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004763
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004764 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004765 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004766 if (ret != NULL)
4767 return(ret);
4768 }
Owen Taylor3473f882001-02-23 17:55:21 +00004769 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4770}
4771
4772/**
4773 * xmlXPathFunctionLookupNS:
4774 * @ctxt: the XPath context
4775 * @name: the function name
4776 * @ns_uri: the function namespace URI
4777 *
4778 * Search in the Function array of the context for the given
4779 * function.
4780 *
4781 * Returns the xmlXPathFunction or NULL if not found
4782 */
4783xmlXPathFunction
4784xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4785 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00004786 xmlXPathFunction ret;
4787
Owen Taylor3473f882001-02-23 17:55:21 +00004788 if (ctxt == NULL)
4789 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004790 if (name == NULL)
4791 return(NULL);
4792
Thomas Broyerba4ad322001-07-26 16:55:21 +00004793 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004794 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004795
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004796 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004797 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004798 if (ret != NULL)
4799 return(ret);
4800 }
4801
4802 if (ctxt->funcHash == NULL)
4803 return(NULL);
4804
William M. Brackad0e67c2004-12-01 14:35:10 +00004805 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4806 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004807}
4808
4809/**
4810 * xmlXPathRegisteredFuncsCleanup:
4811 * @ctxt: the XPath context
4812 *
4813 * Cleanup the XPath context data associated to registered functions
4814 */
4815void
4816xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4817 if (ctxt == NULL)
4818 return;
4819
4820 xmlHashFree(ctxt->funcHash, NULL);
4821 ctxt->funcHash = NULL;
4822}
4823
4824/************************************************************************
4825 * *
William M. Brack08171912003-12-29 02:52:11 +00004826 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00004827 * *
4828 ************************************************************************/
4829
4830/**
4831 * xmlXPathRegisterVariable:
4832 * @ctxt: the XPath context
4833 * @name: the variable name
4834 * @value: the variable value or NULL
4835 *
4836 * Register a new variable value. If @value is NULL it unregisters
4837 * the variable
4838 *
4839 * Returns 0 in case of success, -1 in case of error
4840 */
4841int
4842xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4843 xmlXPathObjectPtr value) {
4844 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4845}
4846
4847/**
4848 * xmlXPathRegisterVariableNS:
4849 * @ctxt: the XPath context
4850 * @name: the variable name
4851 * @ns_uri: the variable namespace URI
4852 * @value: the variable value or NULL
4853 *
4854 * Register a new variable value. If @value is NULL it unregisters
4855 * the variable
4856 *
4857 * Returns 0 in case of success, -1 in case of error
4858 */
4859int
4860xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4861 const xmlChar *ns_uri,
4862 xmlXPathObjectPtr value) {
4863 if (ctxt == NULL)
4864 return(-1);
4865 if (name == NULL)
4866 return(-1);
4867
4868 if (ctxt->varHash == NULL)
4869 ctxt->varHash = xmlHashCreate(0);
4870 if (ctxt->varHash == NULL)
4871 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004872 if (value == NULL)
4873 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4874 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00004875 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4876 (void *) value,
4877 (xmlHashDeallocator)xmlXPathFreeObject));
4878}
4879
4880/**
4881 * xmlXPathRegisterVariableLookup:
4882 * @ctxt: the XPath context
4883 * @f: the lookup function
4884 * @data: the lookup data
4885 *
4886 * register an external mechanism to do variable lookup
4887 */
4888void
4889xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4890 xmlXPathVariableLookupFunc f, void *data) {
4891 if (ctxt == NULL)
4892 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004893 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00004894 ctxt->varLookupData = data;
4895}
4896
4897/**
4898 * xmlXPathVariableLookup:
4899 * @ctxt: the XPath context
4900 * @name: the variable name
4901 *
4902 * Search in the Variable array of the context for the given
4903 * variable value.
4904 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00004905 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00004906 */
4907xmlXPathObjectPtr
4908xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4909 if (ctxt == NULL)
4910 return(NULL);
4911
4912 if (ctxt->varLookupFunc != NULL) {
4913 xmlXPathObjectPtr ret;
4914
4915 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4916 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00004917 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004918 }
4919 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4920}
4921
4922/**
4923 * xmlXPathVariableLookupNS:
4924 * @ctxt: the XPath context
4925 * @name: the variable name
4926 * @ns_uri: the variable namespace URI
4927 *
4928 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00004929 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00004930 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00004931 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00004932 */
4933xmlXPathObjectPtr
4934xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4935 const xmlChar *ns_uri) {
4936 if (ctxt == NULL)
4937 return(NULL);
4938
4939 if (ctxt->varLookupFunc != NULL) {
4940 xmlXPathObjectPtr ret;
4941
4942 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4943 (ctxt->varLookupData, name, ns_uri);
4944 if (ret != NULL) return(ret);
4945 }
4946
4947 if (ctxt->varHash == NULL)
4948 return(NULL);
4949 if (name == NULL)
4950 return(NULL);
4951
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004952 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
Daniel Veillard8c357d52001-07-03 23:43:33 +00004953 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00004954}
4955
4956/**
4957 * xmlXPathRegisteredVariablesCleanup:
4958 * @ctxt: the XPath context
4959 *
4960 * Cleanup the XPath context data associated to registered variables
4961 */
4962void
4963xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4964 if (ctxt == NULL)
4965 return;
4966
Daniel Veillard76d66f42001-05-16 21:05:17 +00004967 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00004968 ctxt->varHash = NULL;
4969}
4970
4971/**
4972 * xmlXPathRegisterNs:
4973 * @ctxt: the XPath context
4974 * @prefix: the namespace prefix
4975 * @ns_uri: the namespace name
4976 *
4977 * Register a new namespace. If @ns_uri is NULL it unregisters
4978 * the namespace
4979 *
4980 * Returns 0 in case of success, -1 in case of error
4981 */
4982int
4983xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
4984 const xmlChar *ns_uri) {
4985 if (ctxt == NULL)
4986 return(-1);
4987 if (prefix == NULL)
4988 return(-1);
4989
4990 if (ctxt->nsHash == NULL)
4991 ctxt->nsHash = xmlHashCreate(10);
4992 if (ctxt->nsHash == NULL)
4993 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00004994 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00004995 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00004996 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00004997 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00004998 (xmlHashDeallocator)xmlFree));
4999}
5000
5001/**
5002 * xmlXPathNsLookup:
5003 * @ctxt: the XPath context
5004 * @prefix: the namespace prefix value
5005 *
5006 * Search in the namespace declaration array of the context for the given
5007 * namespace name associated to the given prefix
5008 *
5009 * Returns the value or NULL if not found
5010 */
5011const xmlChar *
5012xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5013 if (ctxt == NULL)
5014 return(NULL);
5015 if (prefix == NULL)
5016 return(NULL);
5017
5018#ifdef XML_XML_NAMESPACE
5019 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5020 return(XML_XML_NAMESPACE);
5021#endif
5022
Daniel Veillardc8f620b2001-04-30 20:31:33 +00005023 if (ctxt->namespaces != NULL) {
5024 int i;
5025
5026 for (i = 0;i < ctxt->nsNr;i++) {
5027 if ((ctxt->namespaces[i] != NULL) &&
5028 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5029 return(ctxt->namespaces[i]->href);
5030 }
5031 }
Owen Taylor3473f882001-02-23 17:55:21 +00005032
5033 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5034}
5035
5036/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005037 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00005038 * @ctxt: the XPath context
5039 *
5040 * Cleanup the XPath context data associated to registered variables
5041 */
5042void
5043xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5044 if (ctxt == NULL)
5045 return;
5046
Daniel Veillard42766c02002-08-22 20:52:17 +00005047 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00005048 ctxt->nsHash = NULL;
5049}
5050
5051/************************************************************************
5052 * *
5053 * Routines to handle Values *
5054 * *
5055 ************************************************************************/
5056
William M. Brack08171912003-12-29 02:52:11 +00005057/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005058
5059/**
5060 * xmlXPathNewFloat:
5061 * @val: the double value
5062 *
5063 * Create a new xmlXPathObjectPtr of type double and of value @val
5064 *
5065 * Returns the newly created object.
5066 */
5067xmlXPathObjectPtr
5068xmlXPathNewFloat(double val) {
5069 xmlXPathObjectPtr ret;
5070
5071 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5072 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005073 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005074 return(NULL);
5075 }
5076 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5077 ret->type = XPATH_NUMBER;
5078 ret->floatval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005079#ifdef XP_DEBUG_OBJ_USAGE
5080 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5081#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005082 return(ret);
5083}
5084
5085/**
5086 * xmlXPathNewBoolean:
5087 * @val: the boolean value
5088 *
5089 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5090 *
5091 * Returns the newly created object.
5092 */
5093xmlXPathObjectPtr
5094xmlXPathNewBoolean(int val) {
5095 xmlXPathObjectPtr ret;
5096
5097 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5098 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005099 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005100 return(NULL);
5101 }
5102 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5103 ret->type = XPATH_BOOLEAN;
5104 ret->boolval = (val != 0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005105#ifdef XP_DEBUG_OBJ_USAGE
5106 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5107#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005108 return(ret);
5109}
5110
5111/**
5112 * xmlXPathNewString:
5113 * @val: the xmlChar * value
5114 *
5115 * Create a new xmlXPathObjectPtr of type string and of value @val
5116 *
5117 * Returns the newly created object.
5118 */
5119xmlXPathObjectPtr
5120xmlXPathNewString(const xmlChar *val) {
5121 xmlXPathObjectPtr ret;
5122
5123 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5124 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005125 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005126 return(NULL);
5127 }
5128 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5129 ret->type = XPATH_STRING;
5130 if (val != NULL)
5131 ret->stringval = xmlStrdup(val);
5132 else
5133 ret->stringval = xmlStrdup((const xmlChar *)"");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005134#ifdef XP_DEBUG_OBJ_USAGE
5135 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5136#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005137 return(ret);
5138}
5139
5140/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005141 * xmlXPathWrapString:
5142 * @val: the xmlChar * value
5143 *
5144 * Wraps the @val string into an XPath object.
5145 *
5146 * Returns the newly created object.
5147 */
5148xmlXPathObjectPtr
5149xmlXPathWrapString (xmlChar *val) {
5150 xmlXPathObjectPtr ret;
5151
5152 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5153 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005154 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005155 return(NULL);
5156 }
5157 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5158 ret->type = XPATH_STRING;
5159 ret->stringval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005160#ifdef XP_DEBUG_OBJ_USAGE
5161 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5162#endif
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005163 return(ret);
5164}
5165
5166/**
Owen Taylor3473f882001-02-23 17:55:21 +00005167 * xmlXPathNewCString:
5168 * @val: the char * value
5169 *
5170 * Create a new xmlXPathObjectPtr of type string and of value @val
5171 *
5172 * Returns the newly created object.
5173 */
5174xmlXPathObjectPtr
5175xmlXPathNewCString(const char *val) {
5176 xmlXPathObjectPtr ret;
5177
5178 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5179 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005180 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005181 return(NULL);
5182 }
5183 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5184 ret->type = XPATH_STRING;
5185 ret->stringval = xmlStrdup(BAD_CAST val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005186#ifdef XP_DEBUG_OBJ_USAGE
5187 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5188#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005189 return(ret);
5190}
5191
5192/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005193 * xmlXPathWrapCString:
5194 * @val: the char * value
5195 *
5196 * Wraps a string into an XPath object.
5197 *
5198 * Returns the newly created object.
5199 */
5200xmlXPathObjectPtr
5201xmlXPathWrapCString (char * val) {
5202 return(xmlXPathWrapString((xmlChar *)(val)));
5203}
5204
5205/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005206 * xmlXPathWrapExternal:
5207 * @val: the user data
5208 *
5209 * Wraps the @val data into an XPath object.
5210 *
5211 * Returns the newly created object.
5212 */
5213xmlXPathObjectPtr
5214xmlXPathWrapExternal (void *val) {
5215 xmlXPathObjectPtr ret;
5216
5217 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5218 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005219 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005220 return(NULL);
5221 }
5222 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5223 ret->type = XPATH_USERS;
5224 ret->user = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005225#ifdef XP_DEBUG_OBJ_USAGE
5226 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5227#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005228 return(ret);
5229}
5230
5231/**
Owen Taylor3473f882001-02-23 17:55:21 +00005232 * xmlXPathObjectCopy:
5233 * @val: the original object
5234 *
5235 * allocate a new copy of a given object
5236 *
5237 * Returns the newly created object.
5238 */
5239xmlXPathObjectPtr
5240xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5241 xmlXPathObjectPtr ret;
5242
5243 if (val == NULL)
5244 return(NULL);
5245
5246 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5247 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005248 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005249 return(NULL);
5250 }
5251 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005252#ifdef XP_DEBUG_OBJ_USAGE
5253 xmlXPathDebugObjUsageRequested(NULL, val->type);
5254#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005255 switch (val->type) {
5256 case XPATH_BOOLEAN:
5257 case XPATH_NUMBER:
5258 case XPATH_POINT:
5259 case XPATH_RANGE:
5260 break;
5261 case XPATH_STRING:
5262 ret->stringval = xmlStrdup(val->stringval);
5263 break;
5264 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00005265#if 0
5266/*
5267 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5268 this previous handling is no longer correct, and can cause some serious
5269 problems (ref. bug 145547)
5270*/
Owen Taylor3473f882001-02-23 17:55:21 +00005271 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005272 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005273 xmlNodePtr cur, tmp;
5274 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005275
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005276 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005277 top = xmlNewDoc(NULL);
5278 top->name = (char *)
5279 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005280 ret->user = top;
5281 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005282 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005283 cur = val->nodesetval->nodeTab[0]->children;
5284 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005285 tmp = xmlDocCopyNode(cur, top, 1);
5286 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005287 cur = cur->next;
5288 }
5289 }
William M. Bracke9449c52004-07-11 14:41:20 +00005290
Daniel Veillard9adc0462003-03-24 18:39:54 +00005291 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005292 } else
Owen Taylor3473f882001-02-23 17:55:21 +00005293 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005294 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00005295 break;
William M. Bracke9449c52004-07-11 14:41:20 +00005296#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005297 case XPATH_NODESET:
5298 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005299 /* Do not deallocate the copied tree value */
5300 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005301 break;
5302 case XPATH_LOCATIONSET:
5303#ifdef LIBXML_XPTR_ENABLED
5304 {
5305 xmlLocationSetPtr loc = val->user;
5306 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5307 break;
5308 }
5309#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00005310 case XPATH_USERS:
5311 ret->user = val->user;
5312 break;
5313 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00005314 xmlGenericError(xmlGenericErrorContext,
5315 "xmlXPathObjectCopy: unsupported type %d\n",
5316 val->type);
5317 break;
5318 }
5319 return(ret);
5320}
5321
5322/**
5323 * xmlXPathFreeObject:
5324 * @obj: the object to free
5325 *
5326 * Free up an xmlXPathObjectPtr object.
5327 */
5328void
5329xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5330 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005331 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00005332 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00005333#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005334 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005335 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00005336 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00005337 } else
5338#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005339 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
William M. Bracke9449c52004-07-11 14:41:20 +00005340 if (obj->nodesetval != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005341 xmlXPathFreeValueTree(obj->nodesetval);
Daniel Veillard77851712001-02-27 21:54:07 +00005342 } else {
5343 if (obj->nodesetval != NULL)
5344 xmlXPathFreeNodeSet(obj->nodesetval);
5345 }
Owen Taylor3473f882001-02-23 17:55:21 +00005346#ifdef LIBXML_XPTR_ENABLED
5347 } else if (obj->type == XPATH_LOCATIONSET) {
5348 if (obj->user != NULL)
5349 xmlXPtrFreeLocationSet(obj->user);
5350#endif
5351 } else if (obj->type == XPATH_STRING) {
5352 if (obj->stringval != NULL)
5353 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005354 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005355#ifdef XP_DEBUG_OBJ_USAGE
5356 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5357#endif
5358 xmlFree(obj);
5359}
Owen Taylor3473f882001-02-23 17:55:21 +00005360
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005361/**
5362 * xmlXPathReleaseObject:
5363 * @obj: the xmlXPathObjectPtr to free or to cache
5364 *
5365 * Depending on the state of the cache this frees the given
5366 * XPath object or stores it in the cache.
5367 */
5368static void
5369xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5370{
5371#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5372 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5373 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5374
5375#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5376
5377 if (obj == NULL)
5378 return;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005379 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005380 xmlXPathFreeObject(obj);
5381 } else {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005382 xmlXPathContextCachePtr cache =
5383 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005384
5385 switch (obj->type) {
5386 case XPATH_NODESET:
5387 case XPATH_XSLT_TREE:
5388 if (obj->nodesetval != NULL) {
5389 if (obj->boolval) {
5390 /*
5391 * It looks like the @boolval is used for
5392 * evaluation if this an XSLT Result Tree Fragment.
5393 * TODO: Check if this assumption is correct.
5394 */
5395 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5396 xmlXPathFreeValueTree(obj->nodesetval);
5397 obj->nodesetval = NULL;
5398 } else if ((obj->nodesetval->nodeMax <= 40) &&
5399 (XP_CACHE_WANTS(cache->nodesetObjs,
5400 cache->maxNodeset)))
5401 {
5402 XP_CACHE_ADD(cache->nodesetObjs, obj);
5403 goto obj_cached;
5404 } else {
5405 xmlXPathFreeNodeSet(obj->nodesetval);
5406 obj->nodesetval = NULL;
5407 }
5408 }
5409 break;
5410 case XPATH_STRING:
5411 if (obj->stringval != NULL)
5412 xmlFree(obj->stringval);
5413
5414 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5415 XP_CACHE_ADD(cache->stringObjs, obj);
5416 goto obj_cached;
5417 }
5418 break;
5419 case XPATH_BOOLEAN:
5420 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5421 XP_CACHE_ADD(cache->booleanObjs, obj);
5422 goto obj_cached;
5423 }
5424 break;
5425 case XPATH_NUMBER:
5426 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5427 XP_CACHE_ADD(cache->numberObjs, obj);
5428 goto obj_cached;
5429 }
5430 break;
5431#ifdef LIBXML_XPTR_ENABLED
5432 case XPATH_LOCATIONSET:
5433 if (obj->user != NULL) {
5434 xmlXPtrFreeLocationSet(obj->user);
5435 }
5436 goto free_obj;
5437#endif
5438 default:
5439 goto free_obj;
5440 }
5441
5442 /*
5443 * Fallback to adding to the misc-objects slot.
5444 */
5445 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5446 XP_CACHE_ADD(cache->miscObjs, obj);
5447 } else
5448 goto free_obj;
5449
5450obj_cached:
5451
5452#ifdef XP_DEBUG_OBJ_USAGE
5453 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5454#endif
5455
5456 if (obj->nodesetval != NULL) {
5457 xmlNodeSetPtr tmpset = obj->nodesetval;
5458
5459 /*
5460 * TODO: Due to those nasty ns-nodes, we need to traverse
5461 * the list and free the ns-nodes.
5462 * URGENT TODO: Check if it's actually slowing things down.
5463 * Maybe we shouldn't try to preserve the list.
5464 */
5465 if (tmpset->nodeNr > 1) {
5466 int i;
5467 xmlNodePtr node;
5468
5469 for (i = 0; i < tmpset->nodeNr; i++) {
5470 node = tmpset->nodeTab[i];
5471 if ((node != NULL) &&
5472 (node->type == XML_NAMESPACE_DECL))
5473 {
5474 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5475 }
5476 }
5477 } else if (tmpset->nodeNr == 1) {
5478 if ((tmpset->nodeTab[0] != NULL) &&
5479 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5480 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5481 }
5482 tmpset->nodeNr = 0;
5483 memset(obj, 0, sizeof(xmlXPathObject));
5484 obj->nodesetval = tmpset;
5485 } else
5486 memset(obj, 0, sizeof(xmlXPathObject));
5487
5488 return;
5489
5490free_obj:
5491 /*
5492 * Cache is full; free the object.
5493 */
5494 if (obj->nodesetval != NULL)
5495 xmlXPathFreeNodeSet(obj->nodesetval);
5496#ifdef XP_DEBUG_OBJ_USAGE
5497 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5498#endif
5499 xmlFree(obj);
5500 }
5501 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005502}
5503
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005504
5505/************************************************************************
5506 * *
5507 * Type Casting Routines *
5508 * *
5509 ************************************************************************/
5510
5511/**
5512 * xmlXPathCastBooleanToString:
5513 * @val: a boolean
5514 *
5515 * Converts a boolean to its string value.
5516 *
5517 * Returns a newly allocated string.
5518 */
5519xmlChar *
5520xmlXPathCastBooleanToString (int val) {
5521 xmlChar *ret;
5522 if (val)
5523 ret = xmlStrdup((const xmlChar *) "true");
5524 else
5525 ret = xmlStrdup((const xmlChar *) "false");
5526 return(ret);
5527}
5528
5529/**
5530 * xmlXPathCastNumberToString:
5531 * @val: a number
5532 *
5533 * Converts a number to its string value.
5534 *
5535 * Returns a newly allocated string.
5536 */
5537xmlChar *
5538xmlXPathCastNumberToString (double val) {
5539 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00005540 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005541 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005542 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005543 break;
5544 case -1:
5545 ret = xmlStrdup((const xmlChar *) "-Infinity");
5546 break;
5547 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00005548 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005549 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005550 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5551 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005552 } else {
5553 /* could be improved */
5554 char buf[100];
Daniel Veillard11ce4002006-03-10 00:36:23 +00005555 xmlXPathFormatNumber(val, buf, 99);
5556 buf[99] = 0;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005557 ret = xmlStrdup((const xmlChar *) buf);
5558 }
5559 }
5560 return(ret);
5561}
5562
5563/**
5564 * xmlXPathCastNodeToString:
5565 * @node: a node
5566 *
5567 * Converts a node to its string value.
5568 *
5569 * Returns a newly allocated string.
5570 */
5571xmlChar *
5572xmlXPathCastNodeToString (xmlNodePtr node) {
5573 return(xmlNodeGetContent(node));
5574}
5575
5576/**
5577 * xmlXPathCastNodeSetToString:
5578 * @ns: a node-set
5579 *
5580 * Converts a node-set to its string value.
5581 *
5582 * Returns a newly allocated string.
5583 */
5584xmlChar *
5585xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5586 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5587 return(xmlStrdup((const xmlChar *) ""));
5588
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00005589 if (ns->nodeNr > 1)
5590 xmlXPathNodeSetSort(ns);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005591 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5592}
5593
5594/**
5595 * xmlXPathCastToString:
5596 * @val: an XPath object
5597 *
5598 * Converts an existing object to its string() equivalent
5599 *
5600 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005601 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005602 * string object).
5603 */
5604xmlChar *
5605xmlXPathCastToString(xmlXPathObjectPtr val) {
5606 xmlChar *ret = NULL;
5607
5608 if (val == NULL)
5609 return(xmlStrdup((const xmlChar *) ""));
5610 switch (val->type) {
5611 case XPATH_UNDEFINED:
5612#ifdef DEBUG_EXPR
5613 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5614#endif
5615 ret = xmlStrdup((const xmlChar *) "");
5616 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005617 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005618 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005619 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5620 break;
5621 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00005622 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005623 case XPATH_BOOLEAN:
5624 ret = xmlXPathCastBooleanToString(val->boolval);
5625 break;
5626 case XPATH_NUMBER: {
5627 ret = xmlXPathCastNumberToString(val->floatval);
5628 break;
5629 }
5630 case XPATH_USERS:
5631 case XPATH_POINT:
5632 case XPATH_RANGE:
5633 case XPATH_LOCATIONSET:
5634 TODO
5635 ret = xmlStrdup((const xmlChar *) "");
5636 break;
5637 }
5638 return(ret);
5639}
5640
5641/**
5642 * xmlXPathConvertString:
5643 * @val: an XPath object
5644 *
5645 * Converts an existing object to its string() equivalent
5646 *
5647 * Returns the new object, the old one is freed (or the operation
5648 * is done directly on @val)
5649 */
5650xmlXPathObjectPtr
5651xmlXPathConvertString(xmlXPathObjectPtr val) {
5652 xmlChar *res = NULL;
5653
5654 if (val == NULL)
5655 return(xmlXPathNewCString(""));
5656
5657 switch (val->type) {
5658 case XPATH_UNDEFINED:
5659#ifdef DEBUG_EXPR
5660 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5661#endif
5662 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005663 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005664 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005665 res = xmlXPathCastNodeSetToString(val->nodesetval);
5666 break;
5667 case XPATH_STRING:
5668 return(val);
5669 case XPATH_BOOLEAN:
5670 res = xmlXPathCastBooleanToString(val->boolval);
5671 break;
5672 case XPATH_NUMBER:
5673 res = xmlXPathCastNumberToString(val->floatval);
5674 break;
5675 case XPATH_USERS:
5676 case XPATH_POINT:
5677 case XPATH_RANGE:
5678 case XPATH_LOCATIONSET:
5679 TODO;
5680 break;
5681 }
5682 xmlXPathFreeObject(val);
5683 if (res == NULL)
5684 return(xmlXPathNewCString(""));
5685 return(xmlXPathWrapString(res));
5686}
5687
5688/**
5689 * xmlXPathCastBooleanToNumber:
5690 * @val: a boolean
5691 *
5692 * Converts a boolean to its number value
5693 *
5694 * Returns the number value
5695 */
5696double
5697xmlXPathCastBooleanToNumber(int val) {
5698 if (val)
5699 return(1.0);
5700 return(0.0);
5701}
5702
5703/**
5704 * xmlXPathCastStringToNumber:
5705 * @val: a string
5706 *
5707 * Converts a string to its number value
5708 *
5709 * Returns the number value
5710 */
5711double
5712xmlXPathCastStringToNumber(const xmlChar * val) {
5713 return(xmlXPathStringEvalNumber(val));
5714}
5715
5716/**
5717 * xmlXPathCastNodeToNumber:
5718 * @node: a node
5719 *
5720 * Converts a node to its number value
5721 *
5722 * Returns the number value
5723 */
5724double
5725xmlXPathCastNodeToNumber (xmlNodePtr node) {
5726 xmlChar *strval;
5727 double ret;
5728
5729 if (node == NULL)
5730 return(xmlXPathNAN);
5731 strval = xmlXPathCastNodeToString(node);
5732 if (strval == NULL)
5733 return(xmlXPathNAN);
5734 ret = xmlXPathCastStringToNumber(strval);
5735 xmlFree(strval);
5736
5737 return(ret);
5738}
5739
5740/**
5741 * xmlXPathCastNodeSetToNumber:
5742 * @ns: a node-set
5743 *
5744 * Converts a node-set to its number value
5745 *
5746 * Returns the number value
5747 */
5748double
5749xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5750 xmlChar *str;
5751 double ret;
5752
5753 if (ns == NULL)
5754 return(xmlXPathNAN);
5755 str = xmlXPathCastNodeSetToString(ns);
5756 ret = xmlXPathCastStringToNumber(str);
5757 xmlFree(str);
5758 return(ret);
5759}
5760
5761/**
5762 * xmlXPathCastToNumber:
5763 * @val: an XPath object
5764 *
5765 * Converts an XPath object to its number value
5766 *
5767 * Returns the number value
5768 */
5769double
5770xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5771 double ret = 0.0;
5772
5773 if (val == NULL)
5774 return(xmlXPathNAN);
5775 switch (val->type) {
5776 case XPATH_UNDEFINED:
5777#ifdef DEGUB_EXPR
5778 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5779#endif
5780 ret = xmlXPathNAN;
5781 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005782 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005783 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005784 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5785 break;
5786 case XPATH_STRING:
5787 ret = xmlXPathCastStringToNumber(val->stringval);
5788 break;
5789 case XPATH_NUMBER:
5790 ret = val->floatval;
5791 break;
5792 case XPATH_BOOLEAN:
5793 ret = xmlXPathCastBooleanToNumber(val->boolval);
5794 break;
5795 case XPATH_USERS:
5796 case XPATH_POINT:
5797 case XPATH_RANGE:
5798 case XPATH_LOCATIONSET:
5799 TODO;
5800 ret = xmlXPathNAN;
5801 break;
5802 }
5803 return(ret);
5804}
5805
5806/**
5807 * xmlXPathConvertNumber:
5808 * @val: an XPath object
5809 *
5810 * Converts an existing object to its number() equivalent
5811 *
5812 * Returns the new object, the old one is freed (or the operation
5813 * is done directly on @val)
5814 */
5815xmlXPathObjectPtr
5816xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5817 xmlXPathObjectPtr ret;
5818
5819 if (val == NULL)
5820 return(xmlXPathNewFloat(0.0));
5821 if (val->type == XPATH_NUMBER)
5822 return(val);
5823 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5824 xmlXPathFreeObject(val);
5825 return(ret);
5826}
5827
5828/**
5829 * xmlXPathCastNumberToBoolean:
5830 * @val: a number
5831 *
5832 * Converts a number to its boolean value
5833 *
5834 * Returns the boolean value
5835 */
5836int
5837xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00005838 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005839 return(0);
5840 return(1);
5841}
5842
5843/**
5844 * xmlXPathCastStringToBoolean:
5845 * @val: a string
5846 *
5847 * Converts a string to its boolean value
5848 *
5849 * Returns the boolean value
5850 */
5851int
5852xmlXPathCastStringToBoolean (const xmlChar *val) {
5853 if ((val == NULL) || (xmlStrlen(val) == 0))
5854 return(0);
5855 return(1);
5856}
5857
5858/**
5859 * xmlXPathCastNodeSetToBoolean:
5860 * @ns: a node-set
5861 *
5862 * Converts a node-set to its boolean value
5863 *
5864 * Returns the boolean value
5865 */
5866int
5867xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5868 if ((ns == NULL) || (ns->nodeNr == 0))
5869 return(0);
5870 return(1);
5871}
5872
5873/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005874 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005875 * @val: an XPath object
5876 *
5877 * Converts an XPath object to its boolean value
5878 *
5879 * Returns the boolean value
5880 */
5881int
5882xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5883 int ret = 0;
5884
5885 if (val == NULL)
5886 return(0);
5887 switch (val->type) {
5888 case XPATH_UNDEFINED:
5889#ifdef DEBUG_EXPR
5890 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
5891#endif
5892 ret = 0;
5893 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005894 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005895 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005896 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5897 break;
5898 case XPATH_STRING:
5899 ret = xmlXPathCastStringToBoolean(val->stringval);
5900 break;
5901 case XPATH_NUMBER:
5902 ret = xmlXPathCastNumberToBoolean(val->floatval);
5903 break;
5904 case XPATH_BOOLEAN:
5905 ret = val->boolval;
5906 break;
5907 case XPATH_USERS:
5908 case XPATH_POINT:
5909 case XPATH_RANGE:
5910 case XPATH_LOCATIONSET:
5911 TODO;
5912 ret = 0;
5913 break;
5914 }
5915 return(ret);
5916}
5917
5918
5919/**
5920 * xmlXPathConvertBoolean:
5921 * @val: an XPath object
5922 *
5923 * Converts an existing object to its boolean() equivalent
5924 *
5925 * Returns the new object, the old one is freed (or the operation
5926 * is done directly on @val)
5927 */
5928xmlXPathObjectPtr
5929xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
5930 xmlXPathObjectPtr ret;
5931
5932 if (val == NULL)
5933 return(xmlXPathNewBoolean(0));
5934 if (val->type == XPATH_BOOLEAN)
5935 return(val);
5936 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
5937 xmlXPathFreeObject(val);
5938 return(ret);
5939}
5940
Owen Taylor3473f882001-02-23 17:55:21 +00005941/************************************************************************
5942 * *
5943 * Routines to handle XPath contexts *
5944 * *
5945 ************************************************************************/
5946
5947/**
5948 * xmlXPathNewContext:
5949 * @doc: the XML document
5950 *
5951 * Create a new xmlXPathContext
5952 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00005953 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00005954 */
5955xmlXPathContextPtr
5956xmlXPathNewContext(xmlDocPtr doc) {
5957 xmlXPathContextPtr ret;
5958
5959 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
5960 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005961 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005962 return(NULL);
5963 }
5964 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
5965 ret->doc = doc;
5966 ret->node = NULL;
5967
5968 ret->varHash = NULL;
5969
5970 ret->nb_types = 0;
5971 ret->max_types = 0;
5972 ret->types = NULL;
5973
5974 ret->funcHash = xmlHashCreate(0);
5975
5976 ret->nb_axis = 0;
5977 ret->max_axis = 0;
5978 ret->axis = NULL;
5979
5980 ret->nsHash = NULL;
5981 ret->user = NULL;
5982
5983 ret->contextSize = -1;
5984 ret->proximityPosition = -1;
5985
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005986#ifdef XP_DEFAULT_CACHE_ON
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005987 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005988 xmlXPathFreeContext(ret);
5989 return(NULL);
5990 }
5991#endif
5992
5993 xmlXPathRegisterAllFunctions(ret);
5994
Owen Taylor3473f882001-02-23 17:55:21 +00005995 return(ret);
5996}
5997
5998/**
5999 * xmlXPathFreeContext:
6000 * @ctxt: the context to free
6001 *
6002 * Free up an xmlXPathContext
6003 */
6004void
6005xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006006 if (ctxt == NULL) return;
6007
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006008 if (ctxt->cache != NULL)
6009 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
Owen Taylor3473f882001-02-23 17:55:21 +00006010 xmlXPathRegisteredNsCleanup(ctxt);
6011 xmlXPathRegisteredFuncsCleanup(ctxt);
6012 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006013 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00006014 xmlFree(ctxt);
6015}
6016
6017/************************************************************************
6018 * *
6019 * Routines to handle XPath parser contexts *
6020 * *
6021 ************************************************************************/
6022
6023#define CHECK_CTXT(ctxt) \
6024 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00006025 __xmlRaiseError(NULL, NULL, NULL, \
6026 NULL, NULL, XML_FROM_XPATH, \
6027 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6028 __FILE__, __LINE__, \
6029 NULL, NULL, NULL, 0, 0, \
6030 "NULL context pointer\n"); \
6031 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00006032 } \
6033
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006034#define CHECK_CTXT_NEG(ctxt) \
6035 if (ctxt == NULL) { \
6036 __xmlRaiseError(NULL, NULL, NULL, \
6037 NULL, NULL, XML_FROM_XPATH, \
6038 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6039 __FILE__, __LINE__, \
6040 NULL, NULL, NULL, 0, 0, \
6041 "NULL context pointer\n"); \
6042 return(-1); \
6043 } \
6044
Owen Taylor3473f882001-02-23 17:55:21 +00006045
6046#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00006047 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
6048 (ctxt->doc->children == NULL)) { \
6049 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00006050 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00006051 }
Owen Taylor3473f882001-02-23 17:55:21 +00006052
6053
6054/**
6055 * xmlXPathNewParserContext:
6056 * @str: the XPath expression
6057 * @ctxt: the XPath context
6058 *
6059 * Create a new xmlXPathParserContext
6060 *
6061 * Returns the xmlXPathParserContext just allocated.
6062 */
6063xmlXPathParserContextPtr
6064xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6065 xmlXPathParserContextPtr ret;
6066
6067 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6068 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006069 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006070 return(NULL);
6071 }
6072 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6073 ret->cur = ret->base = str;
6074 ret->context = ctxt;
6075
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006076 ret->comp = xmlXPathNewCompExpr();
6077 if (ret->comp == NULL) {
6078 xmlFree(ret->valueTab);
6079 xmlFree(ret);
6080 return(NULL);
6081 }
Daniel Veillard4773df22004-01-23 13:15:13 +00006082 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6083 ret->comp->dict = ctxt->dict;
6084 xmlDictReference(ret->comp->dict);
6085 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006086
6087 return(ret);
6088}
6089
6090/**
6091 * xmlXPathCompParserContext:
6092 * @comp: the XPath compiled expression
6093 * @ctxt: the XPath context
6094 *
6095 * Create a new xmlXPathParserContext when processing a compiled expression
6096 *
6097 * Returns the xmlXPathParserContext just allocated.
6098 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006099static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006100xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6101 xmlXPathParserContextPtr ret;
6102
6103 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6104 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006105 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006106 return(NULL);
6107 }
6108 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6109
Owen Taylor3473f882001-02-23 17:55:21 +00006110 /* Allocate the value stack */
6111 ret->valueTab = (xmlXPathObjectPtr *)
6112 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006113 if (ret->valueTab == NULL) {
6114 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006115 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006116 return(NULL);
6117 }
Owen Taylor3473f882001-02-23 17:55:21 +00006118 ret->valueNr = 0;
6119 ret->valueMax = 10;
6120 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006121
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006122 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006123 ret->comp = comp;
6124
Owen Taylor3473f882001-02-23 17:55:21 +00006125 return(ret);
6126}
6127
6128/**
6129 * xmlXPathFreeParserContext:
6130 * @ctxt: the context to free
6131 *
6132 * Free up an xmlXPathParserContext
6133 */
6134void
6135xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6136 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006137 xmlFree(ctxt->valueTab);
6138 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00006139 if (ctxt->comp != NULL) {
6140#ifdef XPATH_STREAMING
6141 if (ctxt->comp->stream != NULL) {
6142 xmlFreePatternList(ctxt->comp->stream);
6143 ctxt->comp->stream = NULL;
6144 }
6145#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006146 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard56de87e2005-02-16 00:22:29 +00006147 }
Owen Taylor3473f882001-02-23 17:55:21 +00006148 xmlFree(ctxt);
6149}
6150
6151/************************************************************************
6152 * *
6153 * The implicit core function library *
6154 * *
6155 ************************************************************************/
6156
Owen Taylor3473f882001-02-23 17:55:21 +00006157/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006158 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00006159 * @node: a node pointer
6160 *
6161 * Function computing the beginning of the string value of the node,
6162 * used to speed up comparisons
6163 *
6164 * Returns an int usable as a hash
6165 */
6166static unsigned int
6167xmlXPathNodeValHash(xmlNodePtr node) {
6168 int len = 2;
6169 const xmlChar * string = NULL;
6170 xmlNodePtr tmp = NULL;
6171 unsigned int ret = 0;
6172
6173 if (node == NULL)
6174 return(0);
6175
Daniel Veillard9adc0462003-03-24 18:39:54 +00006176 if (node->type == XML_DOCUMENT_NODE) {
6177 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6178 if (tmp == NULL)
6179 node = node->children;
6180 else
6181 node = tmp;
6182
6183 if (node == NULL)
6184 return(0);
6185 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006186
6187 switch (node->type) {
6188 case XML_COMMENT_NODE:
6189 case XML_PI_NODE:
6190 case XML_CDATA_SECTION_NODE:
6191 case XML_TEXT_NODE:
6192 string = node->content;
6193 if (string == NULL)
6194 return(0);
6195 if (string[0] == 0)
6196 return(0);
6197 return(((unsigned int) string[0]) +
6198 (((unsigned int) string[1]) << 8));
6199 case XML_NAMESPACE_DECL:
6200 string = ((xmlNsPtr)node)->href;
6201 if (string == NULL)
6202 return(0);
6203 if (string[0] == 0)
6204 return(0);
6205 return(((unsigned int) string[0]) +
6206 (((unsigned int) string[1]) << 8));
6207 case XML_ATTRIBUTE_NODE:
6208 tmp = ((xmlAttrPtr) node)->children;
6209 break;
6210 case XML_ELEMENT_NODE:
6211 tmp = node->children;
6212 break;
6213 default:
6214 return(0);
6215 }
6216 while (tmp != NULL) {
6217 switch (tmp->type) {
6218 case XML_COMMENT_NODE:
6219 case XML_PI_NODE:
6220 case XML_CDATA_SECTION_NODE:
6221 case XML_TEXT_NODE:
6222 string = tmp->content;
6223 break;
6224 case XML_NAMESPACE_DECL:
6225 string = ((xmlNsPtr)tmp)->href;
6226 break;
6227 default:
6228 break;
6229 }
6230 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006231 if (len == 1) {
6232 return(ret + (((unsigned int) string[0]) << 8));
6233 }
6234 if (string[1] == 0) {
6235 len = 1;
6236 ret = (unsigned int) string[0];
6237 } else {
6238 return(((unsigned int) string[0]) +
6239 (((unsigned int) string[1]) << 8));
6240 }
6241 }
6242 /*
6243 * Skip to next node
6244 */
6245 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6246 if (tmp->children->type != XML_ENTITY_DECL) {
6247 tmp = tmp->children;
6248 continue;
6249 }
6250 }
6251 if (tmp == node)
6252 break;
6253
6254 if (tmp->next != NULL) {
6255 tmp = tmp->next;
6256 continue;
6257 }
6258
6259 do {
6260 tmp = tmp->parent;
6261 if (tmp == NULL)
6262 break;
6263 if (tmp == node) {
6264 tmp = NULL;
6265 break;
6266 }
6267 if (tmp->next != NULL) {
6268 tmp = tmp->next;
6269 break;
6270 }
6271 } while (tmp != NULL);
6272 }
6273 return(ret);
6274}
6275
6276/**
6277 * xmlXPathStringHash:
6278 * @string: a string
6279 *
6280 * Function computing the beginning of the string value of the node,
6281 * used to speed up comparisons
6282 *
6283 * Returns an int usable as a hash
6284 */
6285static unsigned int
6286xmlXPathStringHash(const xmlChar * string) {
6287 if (string == NULL)
6288 return((unsigned int) 0);
6289 if (string[0] == 0)
6290 return(0);
6291 return(((unsigned int) string[0]) +
6292 (((unsigned int) string[1]) << 8));
6293}
6294
6295/**
Owen Taylor3473f882001-02-23 17:55:21 +00006296 * xmlXPathCompareNodeSetFloat:
6297 * @ctxt: the XPath Parser context
6298 * @inf: less than (1) or greater than (0)
6299 * @strict: is the comparison strict
6300 * @arg: the node set
6301 * @f: the value
6302 *
6303 * Implement the compare operation between a nodeset and a number
6304 * @ns < @val (1, 1, ...
6305 * @ns <= @val (1, 0, ...
6306 * @ns > @val (0, 1, ...
6307 * @ns >= @val (0, 0, ...
6308 *
6309 * If one object to be compared is a node-set and the other is a number,
6310 * then the comparison will be true if and only if there is a node in the
6311 * node-set such that the result of performing the comparison on the number
6312 * to be compared and on the result of converting the string-value of that
6313 * node to a number using the number function is true.
6314 *
6315 * Returns 0 or 1 depending on the results of the test.
6316 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006317static int
Owen Taylor3473f882001-02-23 17:55:21 +00006318xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6319 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6320 int i, ret = 0;
6321 xmlNodeSetPtr ns;
6322 xmlChar *str2;
6323
6324 if ((f == NULL) || (arg == NULL) ||
6325 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006326 xmlXPathReleaseObject(ctxt->context, arg);
6327 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006328 return(0);
6329 }
6330 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006331 if (ns != NULL) {
6332 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006333 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006334 if (str2 != NULL) {
6335 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006336 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006337 xmlFree(str2);
6338 xmlXPathNumberFunction(ctxt, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006339 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006340 ret = xmlXPathCompareValues(ctxt, inf, strict);
6341 if (ret)
6342 break;
6343 }
6344 }
Owen Taylor3473f882001-02-23 17:55:21 +00006345 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006346 xmlXPathReleaseObject(ctxt->context, arg);
6347 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006348 return(ret);
6349}
6350
6351/**
6352 * xmlXPathCompareNodeSetString:
6353 * @ctxt: the XPath Parser context
6354 * @inf: less than (1) or greater than (0)
6355 * @strict: is the comparison strict
6356 * @arg: the node set
6357 * @s: the value
6358 *
6359 * Implement the compare operation between a nodeset and a string
6360 * @ns < @val (1, 1, ...
6361 * @ns <= @val (1, 0, ...
6362 * @ns > @val (0, 1, ...
6363 * @ns >= @val (0, 0, ...
6364 *
6365 * If one object to be compared is a node-set and the other is a string,
6366 * then the comparison will be true if and only if there is a node in
6367 * the node-set such that the result of performing the comparison on the
6368 * string-value of the node and the other string is true.
6369 *
6370 * Returns 0 or 1 depending on the results of the test.
6371 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006372static int
Owen Taylor3473f882001-02-23 17:55:21 +00006373xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6374 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6375 int i, ret = 0;
6376 xmlNodeSetPtr ns;
6377 xmlChar *str2;
6378
6379 if ((s == NULL) || (arg == NULL) ||
6380 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006381 xmlXPathReleaseObject(ctxt->context, arg);
6382 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006383 return(0);
6384 }
6385 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006386 if (ns != NULL) {
6387 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006388 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006389 if (str2 != NULL) {
6390 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006391 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006392 xmlFree(str2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006393 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006394 ret = xmlXPathCompareValues(ctxt, inf, strict);
6395 if (ret)
6396 break;
6397 }
6398 }
Owen Taylor3473f882001-02-23 17:55:21 +00006399 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006400 xmlXPathReleaseObject(ctxt->context, arg);
6401 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006402 return(ret);
6403}
6404
6405/**
6406 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006407 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00006408 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006409 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00006410 * @arg2: the second node set object
6411 *
6412 * Implement the compare operation on nodesets:
6413 *
6414 * If both objects to be compared are node-sets, then the comparison
6415 * will be true if and only if there is a node in the first node-set
6416 * and a node in the second node-set such that the result of performing
6417 * the comparison on the string-values of the two nodes is true.
6418 * ....
6419 * When neither object to be compared is a node-set and the operator
6420 * is <=, <, >= or >, then the objects are compared by converting both
6421 * objects to numbers and comparing the numbers according to IEEE 754.
6422 * ....
6423 * The number function converts its argument to a number as follows:
6424 * - a string that consists of optional whitespace followed by an
6425 * optional minus sign followed by a Number followed by whitespace
6426 * is converted to the IEEE 754 number that is nearest (according
6427 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6428 * represented by the string; any other string is converted to NaN
6429 *
6430 * Conclusion all nodes need to be converted first to their string value
6431 * and then the comparison must be done when possible
6432 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006433static int
6434xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00006435 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6436 int i, j, init = 0;
6437 double val1;
6438 double *values2;
6439 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006440 xmlNodeSetPtr ns1;
6441 xmlNodeSetPtr ns2;
6442
6443 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006444 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6445 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006446 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006447 }
Owen Taylor3473f882001-02-23 17:55:21 +00006448 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006449 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6450 xmlXPathFreeObject(arg1);
6451 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006452 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006453 }
Owen Taylor3473f882001-02-23 17:55:21 +00006454
6455 ns1 = arg1->nodesetval;
6456 ns2 = arg2->nodesetval;
6457
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006458 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006459 xmlXPathFreeObject(arg1);
6460 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006461 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006462 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006463 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006464 xmlXPathFreeObject(arg1);
6465 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006466 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006467 }
Owen Taylor3473f882001-02-23 17:55:21 +00006468
6469 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6470 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006471 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00006472 xmlXPathFreeObject(arg1);
6473 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006474 return(0);
6475 }
6476 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006477 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00006478 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00006479 continue;
6480 for (j = 0;j < ns2->nodeNr;j++) {
6481 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006482 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00006483 }
Daniel Veillardcda96922001-08-21 10:56:31 +00006484 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00006485 continue;
6486 if (inf && strict)
6487 ret = (val1 < values2[j]);
6488 else if (inf && !strict)
6489 ret = (val1 <= values2[j]);
6490 else if (!inf && strict)
6491 ret = (val1 > values2[j]);
6492 else if (!inf && !strict)
6493 ret = (val1 >= values2[j]);
6494 if (ret)
6495 break;
6496 }
6497 if (ret)
6498 break;
6499 init = 1;
6500 }
6501 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006502 xmlXPathFreeObject(arg1);
6503 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006504 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006505}
6506
6507/**
6508 * xmlXPathCompareNodeSetValue:
6509 * @ctxt: the XPath Parser context
6510 * @inf: less than (1) or greater than (0)
6511 * @strict: is the comparison strict
6512 * @arg: the node set
6513 * @val: the value
6514 *
6515 * Implement the compare operation between a nodeset and a value
6516 * @ns < @val (1, 1, ...
6517 * @ns <= @val (1, 0, ...
6518 * @ns > @val (0, 1, ...
6519 * @ns >= @val (0, 0, ...
6520 *
6521 * If one object to be compared is a node-set and the other is a boolean,
6522 * then the comparison will be true if and only if the result of performing
6523 * the comparison on the boolean and on the result of converting
6524 * the node-set to a boolean using the boolean function is true.
6525 *
6526 * Returns 0 or 1 depending on the results of the test.
6527 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006528static int
Owen Taylor3473f882001-02-23 17:55:21 +00006529xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6530 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6531 if ((val == NULL) || (arg == NULL) ||
6532 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6533 return(0);
6534
6535 switch(val->type) {
6536 case XPATH_NUMBER:
6537 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6538 case XPATH_NODESET:
6539 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006540 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00006541 case XPATH_STRING:
6542 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6543 case XPATH_BOOLEAN:
6544 valuePush(ctxt, arg);
6545 xmlXPathBooleanFunction(ctxt, 1);
6546 valuePush(ctxt, val);
6547 return(xmlXPathCompareValues(ctxt, inf, strict));
6548 default:
6549 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00006550 }
6551 return(0);
6552}
6553
6554/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006555 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00006556 * @arg: the nodeset object argument
6557 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00006558 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006559 *
6560 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6561 * If one object to be compared is a node-set and the other is a string,
6562 * then the comparison will be true if and only if there is a node in
6563 * the node-set such that the result of performing the comparison on the
6564 * string-value of the node and the other string is true.
6565 *
6566 * Returns 0 or 1 depending on the results of the test.
6567 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006568static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006569xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006570{
Owen Taylor3473f882001-02-23 17:55:21 +00006571 int i;
6572 xmlNodeSetPtr ns;
6573 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006574 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00006575
6576 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00006577 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6578 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006579 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00006580 /*
6581 * A NULL nodeset compared with a string is always false
6582 * (since there is no node equal, and no node not equal)
6583 */
6584 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00006585 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00006586 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006587 for (i = 0; i < ns->nodeNr; i++) {
6588 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6589 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6590 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6591 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006592 if (neq)
6593 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006594 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00006595 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6596 if (neq)
6597 continue;
6598 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006599 } else if (neq) {
6600 if (str2 != NULL)
6601 xmlFree(str2);
6602 return (1);
6603 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006604 if (str2 != NULL)
6605 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006606 } else if (neq)
6607 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00006608 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006609 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006610}
6611
6612/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006613 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00006614 * @arg: the nodeset object argument
6615 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00006616 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006617 *
6618 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6619 * If one object to be compared is a node-set and the other is a number,
6620 * then the comparison will be true if and only if there is a node in
6621 * the node-set such that the result of performing the comparison on the
6622 * number to be compared and on the result of converting the string-value
6623 * of that node to a number using the number function is true.
6624 *
6625 * Returns 0 or 1 depending on the results of the test.
6626 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006627static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006628xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6629 xmlXPathObjectPtr arg, double f, int neq) {
6630 int i, ret=0;
6631 xmlNodeSetPtr ns;
6632 xmlChar *str2;
6633 xmlXPathObjectPtr val;
6634 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00006635
6636 if ((arg == NULL) ||
6637 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6638 return(0);
6639
William M. Brack0c022ad2002-07-12 00:56:01 +00006640 ns = arg->nodesetval;
6641 if (ns != NULL) {
6642 for (i=0;i<ns->nodeNr;i++) {
6643 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6644 if (str2 != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006645 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
William M. Brack0c022ad2002-07-12 00:56:01 +00006646 xmlFree(str2);
6647 xmlXPathNumberFunction(ctxt, 1);
6648 val = valuePop(ctxt);
6649 v = val->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006650 xmlXPathReleaseObject(ctxt->context, val);
William M. Brack0c022ad2002-07-12 00:56:01 +00006651 if (!xmlXPathIsNaN(v)) {
6652 if ((!neq) && (v==f)) {
6653 ret = 1;
6654 break;
6655 } else if ((neq) && (v!=f)) {
6656 ret = 1;
6657 break;
6658 }
William M. Brack32f0f712005-07-14 07:00:33 +00006659 } else { /* NaN is unequal to any value */
6660 if (neq)
6661 ret = 1;
William M. Brack0c022ad2002-07-12 00:56:01 +00006662 }
6663 }
6664 }
6665 }
6666
6667 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006668}
6669
6670
6671/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006672 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00006673 * @arg1: first nodeset object argument
6674 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00006675 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006676 *
William M. Brack0c022ad2002-07-12 00:56:01 +00006677 * Implement the equal / not equal operation on XPath nodesets:
6678 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00006679 * If both objects to be compared are node-sets, then the comparison
6680 * will be true if and only if there is a node in the first node-set and
6681 * a node in the second node-set such that the result of performing the
6682 * comparison on the string-values of the two nodes is true.
6683 *
6684 * (needless to say, this is a costly operation)
6685 *
6686 * Returns 0 or 1 depending on the results of the test.
6687 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006688static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006689xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00006690 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006691 unsigned int *hashs1;
6692 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00006693 xmlChar **values1;
6694 xmlChar **values2;
6695 int ret = 0;
6696 xmlNodeSetPtr ns1;
6697 xmlNodeSetPtr ns2;
6698
6699 if ((arg1 == NULL) ||
6700 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6701 return(0);
6702 if ((arg2 == NULL) ||
6703 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6704 return(0);
6705
6706 ns1 = arg1->nodesetval;
6707 ns2 = arg2->nodesetval;
6708
Daniel Veillard911f49a2001-04-07 15:39:35 +00006709 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006710 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006711 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006712 return(0);
6713
6714 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00006715 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00006716 */
William M. Brack0c022ad2002-07-12 00:56:01 +00006717 if (neq == 0)
6718 for (i = 0;i < ns1->nodeNr;i++)
6719 for (j = 0;j < ns2->nodeNr;j++)
6720 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6721 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006722
6723 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006724 if (values1 == NULL) {
6725 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006726 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006727 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006728 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6729 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006730 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006731 xmlFree(values1);
6732 return(0);
6733 }
Owen Taylor3473f882001-02-23 17:55:21 +00006734 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6735 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6736 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006737 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006738 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00006739 xmlFree(values1);
6740 return(0);
6741 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006742 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6743 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006744 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006745 xmlFree(hashs1);
6746 xmlFree(values1);
6747 xmlFree(values2);
6748 return(0);
6749 }
Owen Taylor3473f882001-02-23 17:55:21 +00006750 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6751 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006752 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006753 for (j = 0;j < ns2->nodeNr;j++) {
6754 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006755 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006756 if (hashs1[i] != hashs2[j]) {
6757 if (neq) {
6758 ret = 1;
6759 break;
6760 }
6761 }
6762 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006763 if (values1[i] == NULL)
6764 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6765 if (values2[j] == NULL)
6766 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006767 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006768 if (ret)
6769 break;
6770 }
Owen Taylor3473f882001-02-23 17:55:21 +00006771 }
6772 if (ret)
6773 break;
6774 }
6775 for (i = 0;i < ns1->nodeNr;i++)
6776 if (values1[i] != NULL)
6777 xmlFree(values1[i]);
6778 for (j = 0;j < ns2->nodeNr;j++)
6779 if (values2[j] != NULL)
6780 xmlFree(values2[j]);
6781 xmlFree(values1);
6782 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006783 xmlFree(hashs1);
6784 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00006785 return(ret);
6786}
6787
William M. Brack0c022ad2002-07-12 00:56:01 +00006788static int
6789xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6790 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00006791 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00006792 /*
6793 *At this point we are assured neither arg1 nor arg2
6794 *is a nodeset, so we can just pick the appropriate routine.
6795 */
Owen Taylor3473f882001-02-23 17:55:21 +00006796 switch (arg1->type) {
6797 case XPATH_UNDEFINED:
6798#ifdef DEBUG_EXPR
6799 xmlGenericError(xmlGenericErrorContext,
6800 "Equal: undefined\n");
6801#endif
6802 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006803 case XPATH_BOOLEAN:
6804 switch (arg2->type) {
6805 case XPATH_UNDEFINED:
6806#ifdef DEBUG_EXPR
6807 xmlGenericError(xmlGenericErrorContext,
6808 "Equal: undefined\n");
6809#endif
6810 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006811 case XPATH_BOOLEAN:
6812#ifdef DEBUG_EXPR
6813 xmlGenericError(xmlGenericErrorContext,
6814 "Equal: %d boolean %d \n",
6815 arg1->boolval, arg2->boolval);
6816#endif
6817 ret = (arg1->boolval == arg2->boolval);
6818 break;
6819 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00006820 ret = (arg1->boolval ==
6821 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006822 break;
6823 case XPATH_STRING:
6824 if ((arg2->stringval == NULL) ||
6825 (arg2->stringval[0] == 0)) ret = 0;
6826 else
6827 ret = 1;
6828 ret = (arg1->boolval == ret);
6829 break;
6830 case XPATH_USERS:
6831 case XPATH_POINT:
6832 case XPATH_RANGE:
6833 case XPATH_LOCATIONSET:
6834 TODO
6835 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006836 case XPATH_NODESET:
6837 case XPATH_XSLT_TREE:
6838 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006839 }
6840 break;
6841 case XPATH_NUMBER:
6842 switch (arg2->type) {
6843 case XPATH_UNDEFINED:
6844#ifdef DEBUG_EXPR
6845 xmlGenericError(xmlGenericErrorContext,
6846 "Equal: undefined\n");
6847#endif
6848 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006849 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00006850 ret = (arg2->boolval==
6851 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006852 break;
6853 case XPATH_STRING:
6854 valuePush(ctxt, arg2);
6855 xmlXPathNumberFunction(ctxt, 1);
6856 arg2 = valuePop(ctxt);
6857 /* no break on purpose */
6858 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006859 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00006860 if (xmlXPathIsNaN(arg1->floatval) ||
6861 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00006862 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006863 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6864 if (xmlXPathIsInf(arg2->floatval) == 1)
6865 ret = 1;
6866 else
6867 ret = 0;
6868 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6869 if (xmlXPathIsInf(arg2->floatval) == -1)
6870 ret = 1;
6871 else
6872 ret = 0;
6873 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6874 if (xmlXPathIsInf(arg1->floatval) == 1)
6875 ret = 1;
6876 else
6877 ret = 0;
6878 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6879 if (xmlXPathIsInf(arg1->floatval) == -1)
6880 ret = 1;
6881 else
6882 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00006883 } else {
6884 ret = (arg1->floatval == arg2->floatval);
6885 }
Owen Taylor3473f882001-02-23 17:55:21 +00006886 break;
6887 case XPATH_USERS:
6888 case XPATH_POINT:
6889 case XPATH_RANGE:
6890 case XPATH_LOCATIONSET:
6891 TODO
6892 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006893 case XPATH_NODESET:
6894 case XPATH_XSLT_TREE:
6895 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006896 }
6897 break;
6898 case XPATH_STRING:
6899 switch (arg2->type) {
6900 case XPATH_UNDEFINED:
6901#ifdef DEBUG_EXPR
6902 xmlGenericError(xmlGenericErrorContext,
6903 "Equal: undefined\n");
6904#endif
6905 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006906 case XPATH_BOOLEAN:
6907 if ((arg1->stringval == NULL) ||
6908 (arg1->stringval[0] == 0)) ret = 0;
6909 else
6910 ret = 1;
6911 ret = (arg2->boolval == ret);
6912 break;
6913 case XPATH_STRING:
6914 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6915 break;
6916 case XPATH_NUMBER:
6917 valuePush(ctxt, arg1);
6918 xmlXPathNumberFunction(ctxt, 1);
6919 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006920 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00006921 if (xmlXPathIsNaN(arg1->floatval) ||
6922 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00006923 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006924 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6925 if (xmlXPathIsInf(arg2->floatval) == 1)
6926 ret = 1;
6927 else
6928 ret = 0;
6929 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6930 if (xmlXPathIsInf(arg2->floatval) == -1)
6931 ret = 1;
6932 else
6933 ret = 0;
6934 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6935 if (xmlXPathIsInf(arg1->floatval) == 1)
6936 ret = 1;
6937 else
6938 ret = 0;
6939 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6940 if (xmlXPathIsInf(arg1->floatval) == -1)
6941 ret = 1;
6942 else
6943 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00006944 } else {
6945 ret = (arg1->floatval == arg2->floatval);
6946 }
Owen Taylor3473f882001-02-23 17:55:21 +00006947 break;
6948 case XPATH_USERS:
6949 case XPATH_POINT:
6950 case XPATH_RANGE:
6951 case XPATH_LOCATIONSET:
6952 TODO
6953 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006954 case XPATH_NODESET:
6955 case XPATH_XSLT_TREE:
6956 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006957 }
6958 break;
6959 case XPATH_USERS:
6960 case XPATH_POINT:
6961 case XPATH_RANGE:
6962 case XPATH_LOCATIONSET:
6963 TODO
6964 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006965 case XPATH_NODESET:
6966 case XPATH_XSLT_TREE:
6967 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006968 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006969 xmlXPathReleaseObject(ctxt->context, arg1);
6970 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006971 return(ret);
6972}
6973
William M. Brack0c022ad2002-07-12 00:56:01 +00006974/**
6975 * xmlXPathEqualValues:
6976 * @ctxt: the XPath Parser context
6977 *
6978 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6979 *
6980 * Returns 0 or 1 depending on the results of the test.
6981 */
6982int
6983xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
6984 xmlXPathObjectPtr arg1, arg2, argtmp;
6985 int ret = 0;
6986
Daniel Veillard6128c012004-11-08 17:16:15 +00006987 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00006988 arg2 = valuePop(ctxt);
6989 arg1 = valuePop(ctxt);
6990 if ((arg1 == NULL) || (arg2 == NULL)) {
6991 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006992 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006993 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006994 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006995 XP_ERROR0(XPATH_INVALID_OPERAND);
6996 }
6997
6998 if (arg1 == arg2) {
6999#ifdef DEBUG_EXPR
7000 xmlGenericError(xmlGenericErrorContext,
7001 "Equal: by pointer\n");
7002#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00007003 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007004 return(1);
7005 }
7006
7007 /*
7008 *If either argument is a nodeset, it's a 'special case'
7009 */
7010 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7011 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7012 /*
7013 *Hack it to assure arg1 is the nodeset
7014 */
7015 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7016 argtmp = arg2;
7017 arg2 = arg1;
7018 arg1 = argtmp;
7019 }
7020 switch (arg2->type) {
7021 case XPATH_UNDEFINED:
7022#ifdef DEBUG_EXPR
7023 xmlGenericError(xmlGenericErrorContext,
7024 "Equal: undefined\n");
7025#endif
7026 break;
7027 case XPATH_NODESET:
7028 case XPATH_XSLT_TREE:
7029 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7030 break;
7031 case XPATH_BOOLEAN:
7032 if ((arg1->nodesetval == NULL) ||
7033 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7034 else
7035 ret = 1;
7036 ret = (ret == arg2->boolval);
7037 break;
7038 case XPATH_NUMBER:
7039 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7040 break;
7041 case XPATH_STRING:
7042 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7043 break;
7044 case XPATH_USERS:
7045 case XPATH_POINT:
7046 case XPATH_RANGE:
7047 case XPATH_LOCATIONSET:
7048 TODO
7049 break;
7050 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007051 xmlXPathReleaseObject(ctxt->context, arg1);
7052 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007053 return(ret);
7054 }
7055
7056 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7057}
7058
7059/**
7060 * xmlXPathNotEqualValues:
7061 * @ctxt: the XPath Parser context
7062 *
7063 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7064 *
7065 * Returns 0 or 1 depending on the results of the test.
7066 */
7067int
7068xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7069 xmlXPathObjectPtr arg1, arg2, argtmp;
7070 int ret = 0;
7071
Daniel Veillard6128c012004-11-08 17:16:15 +00007072 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00007073 arg2 = valuePop(ctxt);
7074 arg1 = valuePop(ctxt);
7075 if ((arg1 == NULL) || (arg2 == NULL)) {
7076 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007077 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007078 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007079 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007080 XP_ERROR0(XPATH_INVALID_OPERAND);
7081 }
7082
7083 if (arg1 == arg2) {
7084#ifdef DEBUG_EXPR
7085 xmlGenericError(xmlGenericErrorContext,
7086 "NotEqual: by pointer\n");
7087#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007088 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007089 return(0);
7090 }
7091
7092 /*
7093 *If either argument is a nodeset, it's a 'special case'
7094 */
7095 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7096 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7097 /*
7098 *Hack it to assure arg1 is the nodeset
7099 */
7100 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7101 argtmp = arg2;
7102 arg2 = arg1;
7103 arg1 = argtmp;
7104 }
7105 switch (arg2->type) {
7106 case XPATH_UNDEFINED:
7107#ifdef DEBUG_EXPR
7108 xmlGenericError(xmlGenericErrorContext,
7109 "NotEqual: undefined\n");
7110#endif
7111 break;
7112 case XPATH_NODESET:
7113 case XPATH_XSLT_TREE:
7114 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7115 break;
7116 case XPATH_BOOLEAN:
7117 if ((arg1->nodesetval == NULL) ||
7118 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7119 else
7120 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00007121 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00007122 break;
7123 case XPATH_NUMBER:
7124 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7125 break;
7126 case XPATH_STRING:
7127 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7128 break;
7129 case XPATH_USERS:
7130 case XPATH_POINT:
7131 case XPATH_RANGE:
7132 case XPATH_LOCATIONSET:
7133 TODO
7134 break;
7135 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007136 xmlXPathReleaseObject(ctxt->context, arg1);
7137 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007138 return(ret);
7139 }
7140
7141 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7142}
Owen Taylor3473f882001-02-23 17:55:21 +00007143
7144/**
7145 * xmlXPathCompareValues:
7146 * @ctxt: the XPath Parser context
7147 * @inf: less than (1) or greater than (0)
7148 * @strict: is the comparison strict
7149 *
7150 * Implement the compare operation on XPath objects:
7151 * @arg1 < @arg2 (1, 1, ...
7152 * @arg1 <= @arg2 (1, 0, ...
7153 * @arg1 > @arg2 (0, 1, ...
7154 * @arg1 >= @arg2 (0, 0, ...
7155 *
7156 * When neither object to be compared is a node-set and the operator is
7157 * <=, <, >=, >, then the objects are compared by converted both objects
7158 * to numbers and comparing the numbers according to IEEE 754. The <
7159 * comparison will be true if and only if the first number is less than the
7160 * second number. The <= comparison will be true if and only if the first
7161 * number is less than or equal to the second number. The > comparison
7162 * will be true if and only if the first number is greater than the second
7163 * number. The >= comparison will be true if and only if the first number
7164 * is greater than or equal to the second number.
7165 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007166 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00007167 */
7168int
7169xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007170 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007171 xmlXPathObjectPtr arg1, arg2;
7172
Daniel Veillard6128c012004-11-08 17:16:15 +00007173 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00007174 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007175 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007176 if ((arg1 == NULL) || (arg2 == NULL)) {
7177 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007178 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007179 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007180 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007181 XP_ERROR0(XPATH_INVALID_OPERAND);
7182 }
7183
William M. Brack0c022ad2002-07-12 00:56:01 +00007184 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7185 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
William M. Brackd6e347e2005-04-15 01:34:41 +00007186 /*
7187 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7188 * are not freed from within this routine; they will be freed from the
7189 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7190 */
William M. Brack0c022ad2002-07-12 00:56:01 +00007191 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7192 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007193 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007194 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00007195 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007196 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7197 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007198 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007199 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7200 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00007201 }
7202 }
7203 return(ret);
7204 }
7205
7206 if (arg1->type != XPATH_NUMBER) {
7207 valuePush(ctxt, arg1);
7208 xmlXPathNumberFunction(ctxt, 1);
7209 arg1 = valuePop(ctxt);
7210 }
7211 if (arg1->type != XPATH_NUMBER) {
7212 xmlXPathFreeObject(arg1);
7213 xmlXPathFreeObject(arg2);
7214 XP_ERROR0(XPATH_INVALID_OPERAND);
7215 }
7216 if (arg2->type != XPATH_NUMBER) {
7217 valuePush(ctxt, arg2);
7218 xmlXPathNumberFunction(ctxt, 1);
7219 arg2 = valuePop(ctxt);
7220 }
7221 if (arg2->type != XPATH_NUMBER) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007222 xmlXPathReleaseObject(ctxt->context, arg1);
7223 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007224 XP_ERROR0(XPATH_INVALID_OPERAND);
7225 }
7226 /*
7227 * Add tests for infinity and nan
7228 * => feedback on 3.4 for Inf and NaN
7229 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007230 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00007231 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007232 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007233 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007234 arg1i=xmlXPathIsInf(arg1->floatval);
7235 arg2i=xmlXPathIsInf(arg2->floatval);
7236 if (inf && strict) {
7237 if ((arg1i == -1 && arg2i != -1) ||
7238 (arg2i == 1 && arg1i != 1)) {
7239 ret = 1;
7240 } else if (arg1i == 0 && arg2i == 0) {
7241 ret = (arg1->floatval < arg2->floatval);
7242 } else {
7243 ret = 0;
7244 }
7245 }
7246 else if (inf && !strict) {
7247 if (arg1i == -1 || arg2i == 1) {
7248 ret = 1;
7249 } else if (arg1i == 0 && arg2i == 0) {
7250 ret = (arg1->floatval <= arg2->floatval);
7251 } else {
7252 ret = 0;
7253 }
7254 }
7255 else if (!inf && strict) {
7256 if ((arg1i == 1 && arg2i != 1) ||
7257 (arg2i == -1 && arg1i != -1)) {
7258 ret = 1;
7259 } else if (arg1i == 0 && arg2i == 0) {
7260 ret = (arg1->floatval > arg2->floatval);
7261 } else {
7262 ret = 0;
7263 }
7264 }
7265 else if (!inf && !strict) {
7266 if (arg1i == 1 || arg2i == -1) {
7267 ret = 1;
7268 } else if (arg1i == 0 && arg2i == 0) {
7269 ret = (arg1->floatval >= arg2->floatval);
7270 } else {
7271 ret = 0;
7272 }
7273 }
Daniel Veillard21458c82002-03-27 16:12:22 +00007274 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007275 xmlXPathReleaseObject(ctxt->context, arg1);
7276 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007277 return(ret);
7278}
7279
7280/**
7281 * xmlXPathValueFlipSign:
7282 * @ctxt: the XPath Parser context
7283 *
7284 * Implement the unary - operation on an XPath object
7285 * The numeric operators convert their operands to numbers as if
7286 * by calling the number function.
7287 */
7288void
7289xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007290 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007291 CAST_TO_NUMBER;
7292 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007293 if (xmlXPathIsNaN(ctxt->value->floatval))
7294 ctxt->value->floatval=xmlXPathNAN;
7295 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7296 ctxt->value->floatval=xmlXPathNINF;
7297 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7298 ctxt->value->floatval=xmlXPathPINF;
7299 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007300 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7301 ctxt->value->floatval = xmlXPathNZERO;
7302 else
7303 ctxt->value->floatval = 0;
7304 }
7305 else
7306 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00007307}
7308
7309/**
7310 * xmlXPathAddValues:
7311 * @ctxt: the XPath Parser context
7312 *
7313 * Implement the add operation on XPath objects:
7314 * The numeric operators convert their operands to numbers as if
7315 * by calling the number function.
7316 */
7317void
7318xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7319 xmlXPathObjectPtr arg;
7320 double val;
7321
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007322 arg = valuePop(ctxt);
7323 if (arg == NULL)
7324 XP_ERROR(XPATH_INVALID_OPERAND);
7325 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007326 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007327 CAST_TO_NUMBER;
7328 CHECK_TYPE(XPATH_NUMBER);
7329 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00007330}
7331
7332/**
7333 * xmlXPathSubValues:
7334 * @ctxt: the XPath Parser context
7335 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007336 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007337 * The numeric operators convert their operands to numbers as if
7338 * by calling the number function.
7339 */
7340void
7341xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7342 xmlXPathObjectPtr arg;
7343 double val;
7344
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007345 arg = valuePop(ctxt);
7346 if (arg == NULL)
7347 XP_ERROR(XPATH_INVALID_OPERAND);
7348 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007349 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007350 CAST_TO_NUMBER;
7351 CHECK_TYPE(XPATH_NUMBER);
7352 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007353}
7354
7355/**
7356 * xmlXPathMultValues:
7357 * @ctxt: the XPath Parser context
7358 *
7359 * Implement the multiply operation on XPath objects:
7360 * The numeric operators convert their operands to numbers as if
7361 * by calling the number function.
7362 */
7363void
7364xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7365 xmlXPathObjectPtr arg;
7366 double val;
7367
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007368 arg = valuePop(ctxt);
7369 if (arg == NULL)
7370 XP_ERROR(XPATH_INVALID_OPERAND);
7371 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007372 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007373 CAST_TO_NUMBER;
7374 CHECK_TYPE(XPATH_NUMBER);
7375 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007376}
7377
7378/**
7379 * xmlXPathDivValues:
7380 * @ctxt: the XPath Parser context
7381 *
7382 * Implement the div operation on XPath objects @arg1 / @arg2:
7383 * The numeric operators convert their operands to numbers as if
7384 * by calling the number function.
7385 */
7386void
7387xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7388 xmlXPathObjectPtr arg;
7389 double val;
7390
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007391 arg = valuePop(ctxt);
7392 if (arg == NULL)
7393 XP_ERROR(XPATH_INVALID_OPERAND);
7394 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007395 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007396 CAST_TO_NUMBER;
7397 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007398 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7399 ctxt->value->floatval = xmlXPathNAN;
7400 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007401 if (ctxt->value->floatval == 0)
7402 ctxt->value->floatval = xmlXPathNAN;
7403 else if (ctxt->value->floatval > 0)
7404 ctxt->value->floatval = xmlXPathNINF;
7405 else if (ctxt->value->floatval < 0)
7406 ctxt->value->floatval = xmlXPathPINF;
7407 }
7408 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007409 if (ctxt->value->floatval == 0)
7410 ctxt->value->floatval = xmlXPathNAN;
7411 else if (ctxt->value->floatval > 0)
7412 ctxt->value->floatval = xmlXPathPINF;
7413 else if (ctxt->value->floatval < 0)
7414 ctxt->value->floatval = xmlXPathNINF;
7415 } else
7416 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007417}
7418
7419/**
7420 * xmlXPathModValues:
7421 * @ctxt: the XPath Parser context
7422 *
7423 * Implement the mod operation on XPath objects: @arg1 / @arg2
7424 * The numeric operators convert their operands to numbers as if
7425 * by calling the number function.
7426 */
7427void
7428xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7429 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00007430 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00007431
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007432 arg = valuePop(ctxt);
7433 if (arg == NULL)
7434 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007435 arg2 = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007436 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007437 CAST_TO_NUMBER;
7438 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007439 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00007440 if (arg2 == 0)
7441 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007442 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00007443 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007444 }
Owen Taylor3473f882001-02-23 17:55:21 +00007445}
7446
7447/************************************************************************
7448 * *
7449 * The traversal functions *
7450 * *
7451 ************************************************************************/
7452
Owen Taylor3473f882001-02-23 17:55:21 +00007453/*
7454 * A traversal function enumerates nodes along an axis.
7455 * Initially it must be called with NULL, and it indicates
7456 * termination on the axis by returning NULL.
7457 */
7458typedef xmlNodePtr (*xmlXPathTraversalFunction)
7459 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7460
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007461/*
7462 * xmlXPathTraversalFunctionExt:
7463 * A traversal function enumerates nodes along an axis.
7464 * Initially it must be called with NULL, and it indicates
7465 * termination on the axis by returning NULL.
7466 * The context node of the traversal is specified via @contextNode.
7467 */
7468typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7469 (xmlNodePtr cur, xmlNodePtr contextNode);
7470
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00007471/*
7472 * xmlXPathNodeSetMergeFunction:
7473 * Used for merging node sets in xmlXPathCollectAndTest().
7474 */
7475typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7476 (xmlNodeSetPtr, xmlNodeSetPtr, int);
7477
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007478
Owen Taylor3473f882001-02-23 17:55:21 +00007479/**
7480 * xmlXPathNextSelf:
7481 * @ctxt: the XPath Parser context
7482 * @cur: the current node in the traversal
7483 *
7484 * Traversal function for the "self" direction
7485 * The self axis contains just the context node itself
7486 *
7487 * Returns the next element following that axis
7488 */
7489xmlNodePtr
7490xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007491 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007492 if (cur == NULL)
7493 return(ctxt->context->node);
7494 return(NULL);
7495}
7496
7497/**
7498 * xmlXPathNextChild:
7499 * @ctxt: the XPath Parser context
7500 * @cur: the current node in the traversal
7501 *
7502 * Traversal function for the "child" direction
7503 * The child axis contains the children of the context node in document order.
7504 *
7505 * Returns the next element following that axis
7506 */
7507xmlNodePtr
7508xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007509 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007510 if (cur == NULL) {
7511 if (ctxt->context->node == NULL) return(NULL);
7512 switch (ctxt->context->node->type) {
7513 case XML_ELEMENT_NODE:
7514 case XML_TEXT_NODE:
7515 case XML_CDATA_SECTION_NODE:
7516 case XML_ENTITY_REF_NODE:
7517 case XML_ENTITY_NODE:
7518 case XML_PI_NODE:
7519 case XML_COMMENT_NODE:
7520 case XML_NOTATION_NODE:
7521 case XML_DTD_NODE:
7522 return(ctxt->context->node->children);
7523 case XML_DOCUMENT_NODE:
7524 case XML_DOCUMENT_TYPE_NODE:
7525 case XML_DOCUMENT_FRAG_NODE:
7526 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007527#ifdef LIBXML_DOCB_ENABLED
7528 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007529#endif
7530 return(((xmlDocPtr) ctxt->context->node)->children);
7531 case XML_ELEMENT_DECL:
7532 case XML_ATTRIBUTE_DECL:
7533 case XML_ENTITY_DECL:
7534 case XML_ATTRIBUTE_NODE:
7535 case XML_NAMESPACE_DECL:
7536 case XML_XINCLUDE_START:
7537 case XML_XINCLUDE_END:
7538 return(NULL);
7539 }
7540 return(NULL);
7541 }
7542 if ((cur->type == XML_DOCUMENT_NODE) ||
7543 (cur->type == XML_HTML_DOCUMENT_NODE))
7544 return(NULL);
7545 return(cur->next);
7546}
7547
7548/**
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00007549 * xmlXPathNextChildElement:
7550 * @ctxt: the XPath Parser context
7551 * @cur: the current node in the traversal
7552 *
7553 * Traversal function for the "child" direction and nodes of type element.
7554 * The child axis contains the children of the context node in document order.
7555 *
7556 * Returns the next element following that axis
7557 */
7558static xmlNodePtr
7559xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7560 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7561 if (cur == NULL) {
7562 cur = ctxt->context->node;
7563 if (cur == NULL) return(NULL);
7564 /*
7565 * Get the first element child.
7566 */
7567 switch (cur->type) {
7568 case XML_ELEMENT_NODE:
7569 case XML_DOCUMENT_FRAG_NODE:
7570 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7571 case XML_ENTITY_NODE:
7572 cur = cur->children;
7573 if (cur != NULL) {
7574 if (cur->type == XML_ELEMENT_NODE)
7575 return(cur);
7576 do {
7577 cur = cur->next;
7578 } while ((cur != NULL) &&
7579 (cur->type != XML_ELEMENT_NODE));
7580 return(cur);
7581 }
7582 return(NULL);
7583 case XML_DOCUMENT_NODE:
7584 case XML_HTML_DOCUMENT_NODE:
7585#ifdef LIBXML_DOCB_ENABLED
7586 case XML_DOCB_DOCUMENT_NODE:
7587#endif
7588 return(xmlDocGetRootElement((xmlDocPtr) cur));
7589 default:
7590 return(NULL);
7591 }
7592 return(NULL);
7593 }
7594 /*
7595 * Get the next sibling element node.
7596 */
7597 switch (cur->type) {
7598 case XML_ELEMENT_NODE:
7599 case XML_TEXT_NODE:
7600 case XML_ENTITY_REF_NODE:
7601 case XML_ENTITY_NODE:
7602 case XML_CDATA_SECTION_NODE:
7603 case XML_PI_NODE:
7604 case XML_COMMENT_NODE:
7605 case XML_XINCLUDE_END:
7606 break;
7607 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7608 default:
7609 return(NULL);
7610 }
7611 if (cur->next != NULL) {
7612 if (cur->next->type == XML_ELEMENT_NODE)
7613 return(cur->next);
7614 cur = cur->next;
7615 do {
7616 cur = cur->next;
7617 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7618 return(cur);
7619 }
7620 return(NULL);
7621}
7622
7623/**
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007624 * xmlXPathNextDescendantOrSelfElemParent:
7625 * @ctxt: the XPath Parser context
7626 * @cur: the current node in the traversal
7627 *
7628 * Traversal function for the "descendant-or-self" axis.
7629 * Additionally it returns only nodes which can be parents of
7630 * element nodes.
7631 *
7632 *
7633 * Returns the next element following that axis
7634 */
7635static xmlNodePtr
7636xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7637 xmlNodePtr contextNode)
7638{
7639 if (cur == NULL) {
7640 if (contextNode == NULL)
7641 return(NULL);
7642 switch (contextNode->type) {
7643 case XML_ELEMENT_NODE:
7644 case XML_XINCLUDE_START:
7645 case XML_DOCUMENT_FRAG_NODE:
7646 case XML_DOCUMENT_NODE:
7647#ifdef LIBXML_DOCB_ENABLED
7648 case XML_DOCB_DOCUMENT_NODE:
7649#endif
7650 case XML_HTML_DOCUMENT_NODE:
7651 return(contextNode);
7652 default:
7653 return(NULL);
7654 }
7655 return(NULL);
7656 } else {
7657 xmlNodePtr start = cur;
7658
7659 while (cur != NULL) {
7660 switch (cur->type) {
7661 case XML_ELEMENT_NODE:
7662 /* TODO: OK to have XInclude here? */
7663 case XML_XINCLUDE_START:
7664 case XML_DOCUMENT_FRAG_NODE:
7665 if (cur != start)
7666 return(cur);
7667 if (cur->children != NULL) {
7668 cur = cur->children;
7669 continue;
7670 }
7671 break;
7672#ifdef LIBXML_DOCB_ENABLED
7673 /* Not sure if we need those here. */
7674 case XML_DOCUMENT_NODE:
7675 case XML_DOCB_DOCUMENT_NODE:
7676#endif
7677 case XML_HTML_DOCUMENT_NODE:
7678 if (cur != start)
7679 return(cur);
7680 return(xmlDocGetRootElement((xmlDocPtr) cur));
7681 default:
7682 break;
7683 }
7684
7685next_sibling:
7686 if ((cur == NULL) || (cur == contextNode))
7687 return(NULL);
7688 if (cur->next != NULL) {
7689 cur = cur->next;
7690 } else {
7691 cur = cur->parent;
7692 goto next_sibling;
7693 }
7694 }
7695 }
7696 return(NULL);
7697}
7698
7699/**
Owen Taylor3473f882001-02-23 17:55:21 +00007700 * xmlXPathNextDescendant:
7701 * @ctxt: the XPath Parser context
7702 * @cur: the current node in the traversal
7703 *
7704 * Traversal function for the "descendant" direction
7705 * the descendant axis contains the descendants of the context node in document
7706 * order; a descendant is a child or a child of a child and so on.
7707 *
7708 * Returns the next element following that axis
7709 */
7710xmlNodePtr
7711xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007712 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007713 if (cur == NULL) {
7714 if (ctxt->context->node == NULL)
7715 return(NULL);
7716 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7717 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7718 return(NULL);
7719
7720 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7721 return(ctxt->context->doc->children);
7722 return(ctxt->context->node->children);
7723 }
7724
Daniel Veillard567e1b42001-08-01 15:53:47 +00007725 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007726 /*
7727 * Do not descend on entities declarations
7728 */
7729 if (cur->children->type != XML_ENTITY_DECL) {
7730 cur = cur->children;
7731 /*
7732 * Skip DTDs
7733 */
7734 if (cur->type != XML_DTD_NODE)
7735 return(cur);
7736 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00007737 }
7738
7739 if (cur == ctxt->context->node) return(NULL);
7740
Daniel Veillard68e9e742002-11-16 15:35:11 +00007741 while (cur->next != NULL) {
7742 cur = cur->next;
7743 if ((cur->type != XML_ENTITY_DECL) &&
7744 (cur->type != XML_DTD_NODE))
7745 return(cur);
7746 }
Owen Taylor3473f882001-02-23 17:55:21 +00007747
7748 do {
7749 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00007750 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00007751 if (cur == ctxt->context->node) return(NULL);
7752 if (cur->next != NULL) {
7753 cur = cur->next;
7754 return(cur);
7755 }
7756 } while (cur != NULL);
7757 return(cur);
7758}
7759
7760/**
7761 * xmlXPathNextDescendantOrSelf:
7762 * @ctxt: the XPath Parser context
7763 * @cur: the current node in the traversal
7764 *
7765 * Traversal function for the "descendant-or-self" direction
7766 * the descendant-or-self axis contains the context node and the descendants
7767 * of the context node in document order; thus the context node is the first
7768 * node on the axis, and the first child of the context node is the second node
7769 * on the axis
7770 *
7771 * Returns the next element following that axis
7772 */
7773xmlNodePtr
7774xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007775 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007776 if (cur == NULL) {
7777 if (ctxt->context->node == NULL)
7778 return(NULL);
7779 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7780 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7781 return(NULL);
7782 return(ctxt->context->node);
7783 }
7784
7785 return(xmlXPathNextDescendant(ctxt, cur));
7786}
7787
7788/**
7789 * xmlXPathNextParent:
7790 * @ctxt: the XPath Parser context
7791 * @cur: the current node in the traversal
7792 *
7793 * Traversal function for the "parent" direction
7794 * The parent axis contains the parent of the context node, if there is one.
7795 *
7796 * Returns the next element following that axis
7797 */
7798xmlNodePtr
7799xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007800 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007801 /*
7802 * the parent of an attribute or namespace node is the element
7803 * to which the attribute or namespace node is attached
7804 * Namespace handling !!!
7805 */
7806 if (cur == NULL) {
7807 if (ctxt->context->node == NULL) return(NULL);
7808 switch (ctxt->context->node->type) {
7809 case XML_ELEMENT_NODE:
7810 case XML_TEXT_NODE:
7811 case XML_CDATA_SECTION_NODE:
7812 case XML_ENTITY_REF_NODE:
7813 case XML_ENTITY_NODE:
7814 case XML_PI_NODE:
7815 case XML_COMMENT_NODE:
7816 case XML_NOTATION_NODE:
7817 case XML_DTD_NODE:
7818 case XML_ELEMENT_DECL:
7819 case XML_ATTRIBUTE_DECL:
7820 case XML_XINCLUDE_START:
7821 case XML_XINCLUDE_END:
7822 case XML_ENTITY_DECL:
7823 if (ctxt->context->node->parent == NULL)
7824 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007825 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007826 ((ctxt->context->node->parent->name[0] == ' ') ||
7827 (xmlStrEqual(ctxt->context->node->parent->name,
7828 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007829 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007830 return(ctxt->context->node->parent);
7831 case XML_ATTRIBUTE_NODE: {
7832 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7833
7834 return(att->parent);
7835 }
7836 case XML_DOCUMENT_NODE:
7837 case XML_DOCUMENT_TYPE_NODE:
7838 case XML_DOCUMENT_FRAG_NODE:
7839 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007840#ifdef LIBXML_DOCB_ENABLED
7841 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007842#endif
7843 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007844 case XML_NAMESPACE_DECL: {
7845 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7846
7847 if ((ns->next != NULL) &&
7848 (ns->next->type != XML_NAMESPACE_DECL))
7849 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00007850 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007851 }
Owen Taylor3473f882001-02-23 17:55:21 +00007852 }
7853 }
7854 return(NULL);
7855}
7856
7857/**
7858 * xmlXPathNextAncestor:
7859 * @ctxt: the XPath Parser context
7860 * @cur: the current node in the traversal
7861 *
7862 * Traversal function for the "ancestor" direction
7863 * the ancestor axis contains the ancestors of the context node; the ancestors
7864 * of the context node consist of the parent of context node and the parent's
7865 * parent and so on; the nodes are ordered in reverse document order; thus the
7866 * parent is the first node on the axis, and the parent's parent is the second
7867 * node on the axis
7868 *
7869 * Returns the next element following that axis
7870 */
7871xmlNodePtr
7872xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007873 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007874 /*
7875 * the parent of an attribute or namespace node is the element
7876 * to which the attribute or namespace node is attached
7877 * !!!!!!!!!!!!!
7878 */
7879 if (cur == NULL) {
7880 if (ctxt->context->node == NULL) return(NULL);
7881 switch (ctxt->context->node->type) {
7882 case XML_ELEMENT_NODE:
7883 case XML_TEXT_NODE:
7884 case XML_CDATA_SECTION_NODE:
7885 case XML_ENTITY_REF_NODE:
7886 case XML_ENTITY_NODE:
7887 case XML_PI_NODE:
7888 case XML_COMMENT_NODE:
7889 case XML_DTD_NODE:
7890 case XML_ELEMENT_DECL:
7891 case XML_ATTRIBUTE_DECL:
7892 case XML_ENTITY_DECL:
7893 case XML_NOTATION_NODE:
7894 case XML_XINCLUDE_START:
7895 case XML_XINCLUDE_END:
7896 if (ctxt->context->node->parent == NULL)
7897 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007898 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007899 ((ctxt->context->node->parent->name[0] == ' ') ||
7900 (xmlStrEqual(ctxt->context->node->parent->name,
7901 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007902 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007903 return(ctxt->context->node->parent);
7904 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007905 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00007906
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007907 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00007908 }
7909 case XML_DOCUMENT_NODE:
7910 case XML_DOCUMENT_TYPE_NODE:
7911 case XML_DOCUMENT_FRAG_NODE:
7912 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007913#ifdef LIBXML_DOCB_ENABLED
7914 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007915#endif
7916 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007917 case XML_NAMESPACE_DECL: {
7918 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7919
7920 if ((ns->next != NULL) &&
7921 (ns->next->type != XML_NAMESPACE_DECL))
7922 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00007923 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00007924 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007925 }
Owen Taylor3473f882001-02-23 17:55:21 +00007926 }
7927 return(NULL);
7928 }
7929 if (cur == ctxt->context->doc->children)
7930 return((xmlNodePtr) ctxt->context->doc);
7931 if (cur == (xmlNodePtr) ctxt->context->doc)
7932 return(NULL);
7933 switch (cur->type) {
7934 case XML_ELEMENT_NODE:
7935 case XML_TEXT_NODE:
7936 case XML_CDATA_SECTION_NODE:
7937 case XML_ENTITY_REF_NODE:
7938 case XML_ENTITY_NODE:
7939 case XML_PI_NODE:
7940 case XML_COMMENT_NODE:
7941 case XML_NOTATION_NODE:
7942 case XML_DTD_NODE:
7943 case XML_ELEMENT_DECL:
7944 case XML_ATTRIBUTE_DECL:
7945 case XML_ENTITY_DECL:
7946 case XML_XINCLUDE_START:
7947 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007948 if (cur->parent == NULL)
7949 return(NULL);
7950 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007951 ((cur->parent->name[0] == ' ') ||
7952 (xmlStrEqual(cur->parent->name,
7953 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007954 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007955 return(cur->parent);
7956 case XML_ATTRIBUTE_NODE: {
7957 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7958
7959 return(att->parent);
7960 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00007961 case XML_NAMESPACE_DECL: {
7962 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7963
7964 if ((ns->next != NULL) &&
7965 (ns->next->type != XML_NAMESPACE_DECL))
7966 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00007967 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00007968 return(NULL);
7969 }
Owen Taylor3473f882001-02-23 17:55:21 +00007970 case XML_DOCUMENT_NODE:
7971 case XML_DOCUMENT_TYPE_NODE:
7972 case XML_DOCUMENT_FRAG_NODE:
7973 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007974#ifdef LIBXML_DOCB_ENABLED
7975 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007976#endif
7977 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007978 }
7979 return(NULL);
7980}
7981
7982/**
7983 * xmlXPathNextAncestorOrSelf:
7984 * @ctxt: the XPath Parser context
7985 * @cur: the current node in the traversal
7986 *
7987 * Traversal function for the "ancestor-or-self" direction
7988 * he ancestor-or-self axis contains the context node and ancestors of
7989 * the context node in reverse document order; thus the context node is
7990 * the first node on the axis, and the context node's parent the second;
7991 * parent here is defined the same as with the parent axis.
7992 *
7993 * Returns the next element following that axis
7994 */
7995xmlNodePtr
7996xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007997 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007998 if (cur == NULL)
7999 return(ctxt->context->node);
8000 return(xmlXPathNextAncestor(ctxt, cur));
8001}
8002
8003/**
8004 * xmlXPathNextFollowingSibling:
8005 * @ctxt: the XPath Parser context
8006 * @cur: the current node in the traversal
8007 *
8008 * Traversal function for the "following-sibling" direction
8009 * The following-sibling axis contains the following siblings of the context
8010 * node in document order.
8011 *
8012 * Returns the next element following that axis
8013 */
8014xmlNodePtr
8015xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008016 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008017 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8018 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8019 return(NULL);
8020 if (cur == (xmlNodePtr) ctxt->context->doc)
8021 return(NULL);
8022 if (cur == NULL)
8023 return(ctxt->context->node->next);
8024 return(cur->next);
8025}
8026
8027/**
8028 * xmlXPathNextPrecedingSibling:
8029 * @ctxt: the XPath Parser context
8030 * @cur: the current node in the traversal
8031 *
8032 * Traversal function for the "preceding-sibling" direction
8033 * The preceding-sibling axis contains the preceding siblings of the context
8034 * node in reverse document order; the first preceding sibling is first on the
8035 * axis; the sibling preceding that node is the second on the axis and so on.
8036 *
8037 * Returns the next element following that axis
8038 */
8039xmlNodePtr
8040xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008041 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008042 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8043 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8044 return(NULL);
8045 if (cur == (xmlNodePtr) ctxt->context->doc)
8046 return(NULL);
8047 if (cur == NULL)
8048 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008049 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8050 cur = cur->prev;
8051 if (cur == NULL)
8052 return(ctxt->context->node->prev);
8053 }
Owen Taylor3473f882001-02-23 17:55:21 +00008054 return(cur->prev);
8055}
8056
8057/**
8058 * xmlXPathNextFollowing:
8059 * @ctxt: the XPath Parser context
8060 * @cur: the current node in the traversal
8061 *
8062 * Traversal function for the "following" direction
8063 * The following axis contains all nodes in the same document as the context
8064 * node that are after the context node in document order, excluding any
8065 * descendants and excluding attribute nodes and namespace nodes; the nodes
8066 * are ordered in document order
8067 *
8068 * Returns the next element following that axis
8069 */
8070xmlNodePtr
8071xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008072 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008073 if (cur != NULL && cur->children != NULL)
8074 return cur->children ;
8075 if (cur == NULL) cur = ctxt->context->node;
8076 if (cur == NULL) return(NULL) ; /* ERROR */
8077 if (cur->next != NULL) return(cur->next) ;
8078 do {
8079 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00008080 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00008081 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8082 if (cur->next != NULL) return(cur->next);
8083 } while (cur != NULL);
8084 return(cur);
8085}
8086
8087/*
8088 * xmlXPathIsAncestor:
8089 * @ancestor: the ancestor node
8090 * @node: the current node
8091 *
8092 * Check that @ancestor is a @node's ancestor
8093 *
8094 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8095 */
8096static int
8097xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8098 if ((ancestor == NULL) || (node == NULL)) return(0);
8099 /* nodes need to be in the same document */
8100 if (ancestor->doc != node->doc) return(0);
8101 /* avoid searching if ancestor or node is the root node */
8102 if (ancestor == (xmlNodePtr) node->doc) return(1);
8103 if (node == (xmlNodePtr) ancestor->doc) return(0);
8104 while (node->parent != NULL) {
8105 if (node->parent == ancestor)
8106 return(1);
8107 node = node->parent;
8108 }
8109 return(0);
8110}
8111
8112/**
8113 * xmlXPathNextPreceding:
8114 * @ctxt: the XPath Parser context
8115 * @cur: the current node in the traversal
8116 *
8117 * Traversal function for the "preceding" direction
8118 * the preceding axis contains all nodes in the same document as the context
8119 * node that are before the context node in document order, excluding any
8120 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8121 * ordered in reverse document order
8122 *
8123 * Returns the next element following that axis
8124 */
8125xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00008126xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8127{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008128 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008129 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008130 cur = ctxt->context->node;
8131 if (cur == NULL)
8132 return (NULL);
8133 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8134 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00008135 do {
8136 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008137 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8138 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008139 }
8140
8141 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008142 if (cur == NULL)
8143 return (NULL);
8144 if (cur == ctxt->context->doc->children)
8145 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008146 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00008147 return (cur);
8148}
8149
8150/**
8151 * xmlXPathNextPrecedingInternal:
8152 * @ctxt: the XPath Parser context
8153 * @cur: the current node in the traversal
8154 *
8155 * Traversal function for the "preceding" direction
8156 * the preceding axis contains all nodes in the same document as the context
8157 * node that are before the context node in document order, excluding any
8158 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8159 * ordered in reverse document order
8160 * This is a faster implementation but internal only since it requires a
8161 * state kept in the parser context: ctxt->ancestor.
8162 *
8163 * Returns the next element following that axis
8164 */
8165static xmlNodePtr
8166xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8167 xmlNodePtr cur)
8168{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008169 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008170 if (cur == NULL) {
8171 cur = ctxt->context->node;
8172 if (cur == NULL)
8173 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00008174 if (cur->type == XML_NAMESPACE_DECL)
8175 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008176 ctxt->ancestor = cur->parent;
8177 }
8178 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8179 cur = cur->prev;
8180 while (cur->prev == NULL) {
8181 cur = cur->parent;
8182 if (cur == NULL)
8183 return (NULL);
8184 if (cur == ctxt->context->doc->children)
8185 return (NULL);
8186 if (cur != ctxt->ancestor)
8187 return (cur);
8188 ctxt->ancestor = cur->parent;
8189 }
8190 cur = cur->prev;
8191 while (cur->last != NULL)
8192 cur = cur->last;
8193 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008194}
8195
8196/**
8197 * xmlXPathNextNamespace:
8198 * @ctxt: the XPath Parser context
8199 * @cur: the current attribute in the traversal
8200 *
8201 * Traversal function for the "namespace" direction
8202 * the namespace axis contains the namespace nodes of the context node;
8203 * the order of nodes on this axis is implementation-defined; the axis will
8204 * be empty unless the context node is an element
8205 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008206 * We keep the XML namespace node at the end of the list.
8207 *
Owen Taylor3473f882001-02-23 17:55:21 +00008208 * Returns the next element following that axis
8209 */
8210xmlNodePtr
8211xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008212 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008213 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00008214 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008215 if (ctxt->context->tmpNsList != NULL)
8216 xmlFree(ctxt->context->tmpNsList);
8217 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00008218 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008219 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00008220 if (ctxt->context->tmpNsList != NULL) {
8221 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8222 ctxt->context->tmpNsNr++;
8223 }
8224 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008225 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008226 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00008227 if (ctxt->context->tmpNsNr > 0) {
8228 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8229 } else {
8230 if (ctxt->context->tmpNsList != NULL)
8231 xmlFree(ctxt->context->tmpNsList);
8232 ctxt->context->tmpNsList = NULL;
8233 return(NULL);
8234 }
Owen Taylor3473f882001-02-23 17:55:21 +00008235}
8236
8237/**
8238 * xmlXPathNextAttribute:
8239 * @ctxt: the XPath Parser context
8240 * @cur: the current attribute in the traversal
8241 *
8242 * Traversal function for the "attribute" direction
8243 * TODO: support DTD inherited default attributes
8244 *
8245 * Returns the next element following that axis
8246 */
8247xmlNodePtr
8248xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008249 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00008250 if (ctxt->context->node == NULL)
8251 return(NULL);
8252 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8253 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008254 if (cur == NULL) {
8255 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8256 return(NULL);
8257 return((xmlNodePtr)ctxt->context->node->properties);
8258 }
8259 return((xmlNodePtr)cur->next);
8260}
8261
8262/************************************************************************
8263 * *
8264 * NodeTest Functions *
8265 * *
8266 ************************************************************************/
8267
Owen Taylor3473f882001-02-23 17:55:21 +00008268#define IS_FUNCTION 200
8269
Owen Taylor3473f882001-02-23 17:55:21 +00008270
8271/************************************************************************
8272 * *
8273 * Implicit tree core function library *
8274 * *
8275 ************************************************************************/
8276
8277/**
8278 * xmlXPathRoot:
8279 * @ctxt: the XPath Parser context
8280 *
8281 * Initialize the context to the root of the document
8282 */
8283void
8284xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008285 if ((ctxt == NULL) || (ctxt->context == NULL))
8286 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008287 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008288 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8289 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008290}
8291
8292/************************************************************************
8293 * *
8294 * The explicit core function library *
8295 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8296 * *
8297 ************************************************************************/
8298
8299
8300/**
8301 * xmlXPathLastFunction:
8302 * @ctxt: the XPath Parser context
8303 * @nargs: the number of arguments
8304 *
8305 * Implement the last() XPath function
8306 * number last()
8307 * The last function returns the number of nodes in the context node list.
8308 */
8309void
8310xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8311 CHECK_ARITY(0);
8312 if (ctxt->context->contextSize >= 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008313 valuePush(ctxt,
8314 xmlXPathCacheNewFloat(ctxt->context,
8315 (double) ctxt->context->contextSize));
Owen Taylor3473f882001-02-23 17:55:21 +00008316#ifdef DEBUG_EXPR
8317 xmlGenericError(xmlGenericErrorContext,
8318 "last() : %d\n", ctxt->context->contextSize);
8319#endif
8320 } else {
8321 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8322 }
8323}
8324
8325/**
8326 * xmlXPathPositionFunction:
8327 * @ctxt: the XPath Parser context
8328 * @nargs: the number of arguments
8329 *
8330 * Implement the position() XPath function
8331 * number position()
8332 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008333 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00008334 * will be equal to last().
8335 */
8336void
8337xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8338 CHECK_ARITY(0);
8339 if (ctxt->context->proximityPosition >= 0) {
8340 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008341 xmlXPathCacheNewFloat(ctxt->context,
8342 (double) ctxt->context->proximityPosition));
Owen Taylor3473f882001-02-23 17:55:21 +00008343#ifdef DEBUG_EXPR
8344 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8345 ctxt->context->proximityPosition);
8346#endif
8347 } else {
8348 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8349 }
8350}
8351
8352/**
8353 * xmlXPathCountFunction:
8354 * @ctxt: the XPath Parser context
8355 * @nargs: the number of arguments
8356 *
8357 * Implement the count() XPath function
8358 * number count(node-set)
8359 */
8360void
8361xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8362 xmlXPathObjectPtr cur;
8363
8364 CHECK_ARITY(1);
8365 if ((ctxt->value == NULL) ||
8366 ((ctxt->value->type != XPATH_NODESET) &&
8367 (ctxt->value->type != XPATH_XSLT_TREE)))
8368 XP_ERROR(XPATH_INVALID_TYPE);
8369 cur = valuePop(ctxt);
8370
Daniel Veillard911f49a2001-04-07 15:39:35 +00008371 if ((cur == NULL) || (cur->nodesetval == NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008372 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00008373 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008374 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8375 (double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00008376 } else {
8377 if ((cur->nodesetval->nodeNr != 1) ||
8378 (cur->nodesetval->nodeTab == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008379 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00008380 } else {
8381 xmlNodePtr tmp;
8382 int i = 0;
8383
8384 tmp = cur->nodesetval->nodeTab[0];
8385 if (tmp != NULL) {
8386 tmp = tmp->children;
8387 while (tmp != NULL) {
8388 tmp = tmp->next;
8389 i++;
8390 }
8391 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008392 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
Daniel Veillardfe703322001-08-14 12:18:09 +00008393 }
8394 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008395 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008396}
8397
8398/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008399 * xmlXPathGetElementsByIds:
8400 * @doc: the document
8401 * @ids: a whitespace separated list of IDs
8402 *
8403 * Selects elements by their unique ID.
8404 *
8405 * Returns a node-set of selected elements.
8406 */
8407static xmlNodeSetPtr
8408xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8409 xmlNodeSetPtr ret;
8410 const xmlChar *cur = ids;
8411 xmlChar *ID;
8412 xmlAttrPtr attr;
8413 xmlNodePtr elem = NULL;
8414
Daniel Veillard7a985a12003-07-06 17:57:42 +00008415 if (ids == NULL) return(NULL);
8416
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008417 ret = xmlXPathNodeSetCreate(NULL);
8418
William M. Brack76e95df2003-10-18 16:20:14 +00008419 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008420 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008421 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00008422 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008423
8424 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00008425 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00008426 /*
8427 * We used to check the fact that the value passed
8428 * was an NCName, but this generated much troubles for
8429 * me and Aleksey Sanin, people blatantly violated that
8430 * constaint, like Visa3D spec.
8431 * if (xmlValidateNCName(ID, 1) == 0)
8432 */
8433 attr = xmlGetID(doc, ID);
8434 if (attr != NULL) {
8435 if (attr->type == XML_ATTRIBUTE_NODE)
8436 elem = attr->parent;
8437 else if (attr->type == XML_ELEMENT_NODE)
8438 elem = (xmlNodePtr) attr;
8439 else
8440 elem = NULL;
8441 if (elem != NULL)
8442 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00008443 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008444 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00008445 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008446
William M. Brack76e95df2003-10-18 16:20:14 +00008447 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008448 ids = cur;
8449 }
8450 return(ret);
8451}
8452
8453/**
Owen Taylor3473f882001-02-23 17:55:21 +00008454 * xmlXPathIdFunction:
8455 * @ctxt: the XPath Parser context
8456 * @nargs: the number of arguments
8457 *
8458 * Implement the id() XPath function
8459 * node-set id(object)
8460 * The id function selects elements by their unique ID
8461 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8462 * then the result is the union of the result of applying id to the
8463 * string value of each of the nodes in the argument node-set. When the
8464 * argument to id is of any other type, the argument is converted to a
8465 * string as if by a call to the string function; the string is split
8466 * into a whitespace-separated list of tokens (whitespace is any sequence
8467 * of characters matching the production S); the result is a node-set
8468 * containing the elements in the same document as the context node that
8469 * have a unique ID equal to any of the tokens in the list.
8470 */
8471void
8472xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008473 xmlChar *tokens;
8474 xmlNodeSetPtr ret;
8475 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00008476
8477 CHECK_ARITY(1);
8478 obj = valuePop(ctxt);
8479 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00008480 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008481 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00008482 int i;
8483
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008484 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008485
Daniel Veillard911f49a2001-04-07 15:39:35 +00008486 if (obj->nodesetval != NULL) {
8487 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008488 tokens =
8489 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8490 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8491 ret = xmlXPathNodeSetMerge(ret, ns);
8492 xmlXPathFreeNodeSet(ns);
8493 if (tokens != NULL)
8494 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00008495 }
Owen Taylor3473f882001-02-23 17:55:21 +00008496 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008497 xmlXPathReleaseObject(ctxt->context, obj);
8498 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00008499 return;
8500 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008501 obj = xmlXPathCacheConvertString(ctxt->context, obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008502 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008503 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8504 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00008505 return;
8506}
8507
8508/**
8509 * xmlXPathLocalNameFunction:
8510 * @ctxt: the XPath Parser context
8511 * @nargs: the number of arguments
8512 *
8513 * Implement the local-name() XPath function
8514 * string local-name(node-set?)
8515 * The local-name function returns a string containing the local part
8516 * of the name of the node in the argument node-set that is first in
8517 * document order. If the node-set is empty or the first node has no
8518 * name, an empty string is returned. If the argument is omitted it
8519 * defaults to the context node.
8520 */
8521void
8522xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8523 xmlXPathObjectPtr cur;
8524
Daniel Veillarda82b1822004-11-08 16:24:57 +00008525 if (ctxt == NULL) return;
8526
Owen Taylor3473f882001-02-23 17:55:21 +00008527 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008528 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8529 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008530 nargs = 1;
8531 }
8532
8533 CHECK_ARITY(1);
8534 if ((ctxt->value == NULL) ||
8535 ((ctxt->value->type != XPATH_NODESET) &&
8536 (ctxt->value->type != XPATH_XSLT_TREE)))
8537 XP_ERROR(XPATH_INVALID_TYPE);
8538 cur = valuePop(ctxt);
8539
Daniel Veillard911f49a2001-04-07 15:39:35 +00008540 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008541 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008542 } else {
8543 int i = 0; /* Should be first in document order !!!!! */
8544 switch (cur->nodesetval->nodeTab[i]->type) {
8545 case XML_ELEMENT_NODE:
8546 case XML_ATTRIBUTE_NODE:
8547 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008548 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008549 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008550 else
8551 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008552 xmlXPathCacheNewString(ctxt->context,
8553 cur->nodesetval->nodeTab[i]->name));
Owen Taylor3473f882001-02-23 17:55:21 +00008554 break;
8555 case XML_NAMESPACE_DECL:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008556 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008557 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8558 break;
8559 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008560 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008561 }
8562 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008563 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008564}
8565
8566/**
8567 * xmlXPathNamespaceURIFunction:
8568 * @ctxt: the XPath Parser context
8569 * @nargs: the number of arguments
8570 *
8571 * Implement the namespace-uri() XPath function
8572 * string namespace-uri(node-set?)
8573 * The namespace-uri function returns a string containing the
8574 * namespace URI of the expanded name of the node in the argument
8575 * node-set that is first in document order. If the node-set is empty,
8576 * the first node has no name, or the expanded name has no namespace
8577 * URI, an empty string is returned. If the argument is omitted it
8578 * defaults to the context node.
8579 */
8580void
8581xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8582 xmlXPathObjectPtr cur;
8583
Daniel Veillarda82b1822004-11-08 16:24:57 +00008584 if (ctxt == NULL) return;
8585
Owen Taylor3473f882001-02-23 17:55:21 +00008586 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008587 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8588 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008589 nargs = 1;
8590 }
8591 CHECK_ARITY(1);
8592 if ((ctxt->value == NULL) ||
8593 ((ctxt->value->type != XPATH_NODESET) &&
8594 (ctxt->value->type != XPATH_XSLT_TREE)))
8595 XP_ERROR(XPATH_INVALID_TYPE);
8596 cur = valuePop(ctxt);
8597
Daniel Veillard911f49a2001-04-07 15:39:35 +00008598 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008599 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008600 } else {
8601 int i = 0; /* Should be first in document order !!!!! */
8602 switch (cur->nodesetval->nodeTab[i]->type) {
8603 case XML_ELEMENT_NODE:
8604 case XML_ATTRIBUTE_NODE:
8605 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008606 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008607 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008608 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008609 cur->nodesetval->nodeTab[i]->ns->href));
8610 break;
8611 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008612 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008613 }
8614 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008615 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008616}
8617
8618/**
8619 * xmlXPathNameFunction:
8620 * @ctxt: the XPath Parser context
8621 * @nargs: the number of arguments
8622 *
8623 * Implement the name() XPath function
8624 * string name(node-set?)
8625 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008626 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00008627 * order. The QName must represent the name with respect to the namespace
8628 * declarations in effect on the node whose name is being represented.
8629 * Typically, this will be the form in which the name occurred in the XML
8630 * source. This need not be the case if there are namespace declarations
8631 * in effect on the node that associate multiple prefixes with the same
8632 * namespace. However, an implementation may include information about
8633 * the original prefix in its representation of nodes; in this case, an
8634 * implementation can ensure that the returned string is always the same
8635 * as the QName used in the XML source. If the argument it omitted it
8636 * defaults to the context node.
8637 * Libxml keep the original prefix so the "real qualified name" used is
8638 * returned.
8639 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008640static void
Daniel Veillard04383752001-07-08 14:27:15 +00008641xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8642{
Owen Taylor3473f882001-02-23 17:55:21 +00008643 xmlXPathObjectPtr cur;
8644
8645 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008646 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8647 ctxt->context->node));
Daniel Veillard04383752001-07-08 14:27:15 +00008648 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008649 }
8650
8651 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00008652 if ((ctxt->value == NULL) ||
8653 ((ctxt->value->type != XPATH_NODESET) &&
8654 (ctxt->value->type != XPATH_XSLT_TREE)))
8655 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00008656 cur = valuePop(ctxt);
8657
Daniel Veillard911f49a2001-04-07 15:39:35 +00008658 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008659 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008660 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00008661 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00008662
Daniel Veillard04383752001-07-08 14:27:15 +00008663 switch (cur->nodesetval->nodeTab[i]->type) {
8664 case XML_ELEMENT_NODE:
8665 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008666 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008667 valuePush(ctxt,
8668 xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008669 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8670 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008671 valuePush(ctxt,
8672 xmlXPathCacheNewString(ctxt->context,
8673 cur->nodesetval->nodeTab[i]->name));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008674 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00008675 xmlChar *fullname;
8676
8677 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8678 cur->nodesetval->nodeTab[i]->ns->prefix,
8679 NULL, 0);
8680 if (fullname == cur->nodesetval->nodeTab[i]->name)
8681 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8682 if (fullname == NULL) {
8683 XP_ERROR(XPATH_MEMORY_ERROR);
8684 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008685 valuePush(ctxt, xmlXPathCacheWrapString(
8686 ctxt->context, fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00008687 }
8688 break;
8689 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008690 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8691 cur->nodesetval->nodeTab[i]));
Daniel Veillard04383752001-07-08 14:27:15 +00008692 xmlXPathLocalNameFunction(ctxt, 1);
8693 }
Owen Taylor3473f882001-02-23 17:55:21 +00008694 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008695 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008696}
8697
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008698
8699/**
Owen Taylor3473f882001-02-23 17:55:21 +00008700 * xmlXPathStringFunction:
8701 * @ctxt: the XPath Parser context
8702 * @nargs: the number of arguments
8703 *
8704 * Implement the string() XPath function
8705 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00008706 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00008707 * - A node-set is converted to a string by returning the value of
8708 * the node in the node-set that is first in document order.
8709 * If the node-set is empty, an empty string is returned.
8710 * - A number is converted to a string as follows
8711 * + NaN is converted to the string NaN
8712 * + positive zero is converted to the string 0
8713 * + negative zero is converted to the string 0
8714 * + positive infinity is converted to the string Infinity
8715 * + negative infinity is converted to the string -Infinity
8716 * + if the number is an integer, the number is represented in
8717 * decimal form as a Number with no decimal point and no leading
8718 * zeros, preceded by a minus sign (-) if the number is negative
8719 * + otherwise, the number is represented in decimal form as a
8720 * Number including a decimal point with at least one digit
8721 * before the decimal point and at least one digit after the
8722 * decimal point, preceded by a minus sign (-) if the number
8723 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008724 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00008725 * before the decimal point; beyond the one required digit
8726 * after the decimal point there must be as many, but only as
8727 * many, more digits as are needed to uniquely distinguish the
8728 * number from all other IEEE 754 numeric values.
8729 * - The boolean false value is converted to the string false.
8730 * The boolean true value is converted to the string true.
8731 *
8732 * If the argument is omitted, it defaults to a node-set with the
8733 * context node as its only member.
8734 */
8735void
8736xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8737 xmlXPathObjectPtr cur;
8738
Daniel Veillarda82b1822004-11-08 16:24:57 +00008739 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008740 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008741 valuePush(ctxt,
8742 xmlXPathCacheWrapString(ctxt->context,
8743 xmlXPathCastNodeToString(ctxt->context->node)));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008744 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008745 }
8746
8747 CHECK_ARITY(1);
8748 cur = valuePop(ctxt);
8749 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008750 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00008751}
8752
8753/**
8754 * xmlXPathStringLengthFunction:
8755 * @ctxt: the XPath Parser context
8756 * @nargs: the number of arguments
8757 *
8758 * Implement the string-length() XPath function
8759 * number string-length(string?)
8760 * The string-length returns the number of characters in the string
8761 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8762 * the context node converted to a string, in other words the value
8763 * of the context node.
8764 */
8765void
8766xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8767 xmlXPathObjectPtr cur;
8768
8769 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008770 if ((ctxt == NULL) || (ctxt->context == NULL))
8771 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008772 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008773 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008774 } else {
8775 xmlChar *content;
8776
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008777 content = xmlXPathCastNodeToString(ctxt->context->node);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008778 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8779 xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00008780 xmlFree(content);
8781 }
8782 return;
8783 }
8784 CHECK_ARITY(1);
8785 CAST_TO_STRING;
8786 CHECK_TYPE(XPATH_STRING);
8787 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008788 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8789 xmlUTF8Strlen(cur->stringval)));
8790 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008791}
8792
8793/**
8794 * xmlXPathConcatFunction:
8795 * @ctxt: the XPath Parser context
8796 * @nargs: the number of arguments
8797 *
8798 * Implement the concat() XPath function
8799 * string concat(string, string, string*)
8800 * The concat function returns the concatenation of its arguments.
8801 */
8802void
8803xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8804 xmlXPathObjectPtr cur, newobj;
8805 xmlChar *tmp;
8806
Daniel Veillarda82b1822004-11-08 16:24:57 +00008807 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008808 if (nargs < 2) {
8809 CHECK_ARITY(2);
8810 }
8811
8812 CAST_TO_STRING;
8813 cur = valuePop(ctxt);
8814 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008815 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008816 return;
8817 }
8818 nargs--;
8819
8820 while (nargs > 0) {
8821 CAST_TO_STRING;
8822 newobj = valuePop(ctxt);
8823 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008824 xmlXPathReleaseObject(ctxt->context, newobj);
8825 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008826 XP_ERROR(XPATH_INVALID_TYPE);
8827 }
8828 tmp = xmlStrcat(newobj->stringval, cur->stringval);
8829 newobj->stringval = cur->stringval;
8830 cur->stringval = tmp;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008831 xmlXPathReleaseObject(ctxt->context, newobj);
Owen Taylor3473f882001-02-23 17:55:21 +00008832 nargs--;
8833 }
8834 valuePush(ctxt, cur);
8835}
8836
8837/**
8838 * xmlXPathContainsFunction:
8839 * @ctxt: the XPath Parser context
8840 * @nargs: the number of arguments
8841 *
8842 * Implement the contains() XPath function
8843 * boolean contains(string, string)
8844 * The contains function returns true if the first argument string
8845 * contains the second argument string, and otherwise returns false.
8846 */
8847void
8848xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8849 xmlXPathObjectPtr hay, needle;
8850
8851 CHECK_ARITY(2);
8852 CAST_TO_STRING;
8853 CHECK_TYPE(XPATH_STRING);
8854 needle = valuePop(ctxt);
8855 CAST_TO_STRING;
8856 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008857
Owen Taylor3473f882001-02-23 17:55:21 +00008858 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008859 xmlXPathReleaseObject(ctxt->context, hay);
8860 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008861 XP_ERROR(XPATH_INVALID_TYPE);
8862 }
8863 if (xmlStrstr(hay->stringval, needle->stringval))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008864 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00008865 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008866 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8867 xmlXPathReleaseObject(ctxt->context, hay);
8868 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008869}
8870
8871/**
8872 * xmlXPathStartsWithFunction:
8873 * @ctxt: the XPath Parser context
8874 * @nargs: the number of arguments
8875 *
8876 * Implement the starts-with() XPath function
8877 * boolean starts-with(string, string)
8878 * The starts-with function returns true if the first argument string
8879 * starts with the second argument string, and otherwise returns false.
8880 */
8881void
8882xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8883 xmlXPathObjectPtr hay, needle;
8884 int n;
8885
8886 CHECK_ARITY(2);
8887 CAST_TO_STRING;
8888 CHECK_TYPE(XPATH_STRING);
8889 needle = valuePop(ctxt);
8890 CAST_TO_STRING;
8891 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008892
Owen Taylor3473f882001-02-23 17:55:21 +00008893 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008894 xmlXPathReleaseObject(ctxt->context, hay);
8895 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008896 XP_ERROR(XPATH_INVALID_TYPE);
8897 }
8898 n = xmlStrlen(needle->stringval);
8899 if (xmlStrncmp(hay->stringval, needle->stringval, n))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008900 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008901 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008902 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8903 xmlXPathReleaseObject(ctxt->context, hay);
8904 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008905}
8906
8907/**
8908 * xmlXPathSubstringFunction:
8909 * @ctxt: the XPath Parser context
8910 * @nargs: the number of arguments
8911 *
8912 * Implement the substring() XPath function
8913 * string substring(string, number, number?)
8914 * The substring function returns the substring of the first argument
8915 * starting at the position specified in the second argument with
8916 * length specified in the third argument. For example,
8917 * substring("12345",2,3) returns "234". If the third argument is not
8918 * specified, it returns the substring starting at the position specified
8919 * in the second argument and continuing to the end of the string. For
8920 * example, substring("12345",2) returns "2345". More precisely, each
8921 * character in the string (see [3.6 Strings]) is considered to have a
8922 * numeric position: the position of the first character is 1, the position
8923 * of the second character is 2 and so on. The returned substring contains
8924 * those characters for which the position of the character is greater than
8925 * or equal to the second argument and, if the third argument is specified,
8926 * less than the sum of the second and third arguments; the comparisons
8927 * and addition used for the above follow the standard IEEE 754 rules. Thus:
8928 * - substring("12345", 1.5, 2.6) returns "234"
8929 * - substring("12345", 0, 3) returns "12"
8930 * - substring("12345", 0 div 0, 3) returns ""
8931 * - substring("12345", 1, 0 div 0) returns ""
8932 * - substring("12345", -42, 1 div 0) returns "12345"
8933 * - substring("12345", -1 div 0, 1 div 0) returns ""
8934 */
8935void
8936xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8937 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00008938 double le=0, in;
8939 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00008940 xmlChar *ret;
8941
Owen Taylor3473f882001-02-23 17:55:21 +00008942 if (nargs < 2) {
8943 CHECK_ARITY(2);
8944 }
8945 if (nargs > 3) {
8946 CHECK_ARITY(3);
8947 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008948 /*
8949 * take care of possible last (position) argument
8950 */
Owen Taylor3473f882001-02-23 17:55:21 +00008951 if (nargs == 3) {
8952 CAST_TO_NUMBER;
8953 CHECK_TYPE(XPATH_NUMBER);
8954 len = valuePop(ctxt);
8955 le = len->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008956 xmlXPathReleaseObject(ctxt->context, len);
Owen Taylor3473f882001-02-23 17:55:21 +00008957 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008958
Owen Taylor3473f882001-02-23 17:55:21 +00008959 CAST_TO_NUMBER;
8960 CHECK_TYPE(XPATH_NUMBER);
8961 start = valuePop(ctxt);
8962 in = start->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008963 xmlXPathReleaseObject(ctxt->context, start);
Owen Taylor3473f882001-02-23 17:55:21 +00008964 CAST_TO_STRING;
8965 CHECK_TYPE(XPATH_STRING);
8966 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00008967 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00008968
Daniel Veillard97ac1312001-05-30 19:14:17 +00008969 /*
8970 * If last pos not present, calculate last position
8971 */
Daniel Veillard9e412302002-06-10 15:59:44 +00008972 if (nargs != 3) {
8973 le = (double)m;
8974 if (in < 1.0)
8975 in = 1.0;
8976 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008977
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008978 /* Need to check for the special cases where either
8979 * the index is NaN, the length is NaN, or both
8980 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00008981 */
Daniel Veillard9e412302002-06-10 15:59:44 +00008982 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008983 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00008984 * To meet the requirements of the spec, the arguments
8985 * must be converted to integer format before
8986 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008987 *
Daniel Veillard9e412302002-06-10 15:59:44 +00008988 * First we go to integer form, rounding up
8989 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008990 */
8991 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00008992 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00008993
Daniel Veillard9e412302002-06-10 15:59:44 +00008994 if (xmlXPathIsInf(le) == 1) {
8995 l = m;
8996 if (i < 1)
8997 i = 1;
8998 }
8999 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9000 l = 0;
9001 else {
9002 l = (int) le;
9003 if (((double)l)+0.5 <= le) l++;
9004 }
9005
9006 /* Now we normalize inidices */
9007 i -= 1;
9008 l += i;
9009 if (i < 0)
9010 i = 0;
9011 if (l > m)
9012 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00009013
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009014 /* number of chars to copy */
9015 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00009016
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009017 ret = xmlUTF8Strsub(str->stringval, i, l);
9018 }
9019 else {
9020 ret = NULL;
9021 }
Owen Taylor3473f882001-02-23 17:55:21 +00009022 if (ret == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009023 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00009024 else {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009025 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009026 xmlFree(ret);
9027 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009028 xmlXPathReleaseObject(ctxt->context, str);
Owen Taylor3473f882001-02-23 17:55:21 +00009029}
9030
9031/**
9032 * xmlXPathSubstringBeforeFunction:
9033 * @ctxt: the XPath Parser context
9034 * @nargs: the number of arguments
9035 *
9036 * Implement the substring-before() XPath function
9037 * string substring-before(string, string)
9038 * The substring-before function returns the substring of the first
9039 * argument string that precedes the first occurrence of the second
9040 * argument string in the first argument string, or the empty string
9041 * if the first argument string does not contain the second argument
9042 * string. For example, substring-before("1999/04/01","/") returns 1999.
9043 */
9044void
9045xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9046 xmlXPathObjectPtr str;
9047 xmlXPathObjectPtr find;
9048 xmlBufferPtr target;
9049 const xmlChar *point;
9050 int offset;
9051
9052 CHECK_ARITY(2);
9053 CAST_TO_STRING;
9054 find = valuePop(ctxt);
9055 CAST_TO_STRING;
9056 str = valuePop(ctxt);
9057
9058 target = xmlBufferCreate();
9059 if (target) {
9060 point = xmlStrstr(str->stringval, find->stringval);
9061 if (point) {
9062 offset = (int)(point - str->stringval);
9063 xmlBufferAdd(target, str->stringval, offset);
9064 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009065 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9066 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00009067 xmlBufferFree(target);
9068 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009069 xmlXPathReleaseObject(ctxt->context, str);
9070 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009071}
9072
9073/**
9074 * xmlXPathSubstringAfterFunction:
9075 * @ctxt: the XPath Parser context
9076 * @nargs: the number of arguments
9077 *
9078 * Implement the substring-after() XPath function
9079 * string substring-after(string, string)
9080 * The substring-after function returns the substring of the first
9081 * argument string that follows the first occurrence of the second
9082 * argument string in the first argument string, or the empty stringi
9083 * if the first argument string does not contain the second argument
9084 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9085 * and substring-after("1999/04/01","19") returns 99/04/01.
9086 */
9087void
9088xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9089 xmlXPathObjectPtr str;
9090 xmlXPathObjectPtr find;
9091 xmlBufferPtr target;
9092 const xmlChar *point;
9093 int offset;
9094
9095 CHECK_ARITY(2);
9096 CAST_TO_STRING;
9097 find = valuePop(ctxt);
9098 CAST_TO_STRING;
9099 str = valuePop(ctxt);
9100
9101 target = xmlBufferCreate();
9102 if (target) {
9103 point = xmlStrstr(str->stringval, find->stringval);
9104 if (point) {
9105 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9106 xmlBufferAdd(target, &str->stringval[offset],
9107 xmlStrlen(str->stringval) - offset);
9108 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009109 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9110 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00009111 xmlBufferFree(target);
9112 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009113 xmlXPathReleaseObject(ctxt->context, str);
9114 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009115}
9116
9117/**
9118 * xmlXPathNormalizeFunction:
9119 * @ctxt: the XPath Parser context
9120 * @nargs: the number of arguments
9121 *
9122 * Implement the normalize-space() XPath function
9123 * string normalize-space(string?)
9124 * The normalize-space function returns the argument string with white
9125 * space normalized by stripping leading and trailing whitespace
9126 * and replacing sequences of whitespace characters by a single
9127 * space. Whitespace characters are the same allowed by the S production
9128 * in XML. If the argument is omitted, it defaults to the context
9129 * node converted to a string, in other words the value of the context node.
9130 */
9131void
9132xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9133 xmlXPathObjectPtr obj = NULL;
9134 xmlChar *source = NULL;
9135 xmlBufferPtr target;
9136 xmlChar blank;
9137
Daniel Veillarda82b1822004-11-08 16:24:57 +00009138 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009139 if (nargs == 0) {
9140 /* Use current context node */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009141 valuePush(ctxt,
9142 xmlXPathCacheWrapString(ctxt->context,
9143 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00009144 nargs = 1;
9145 }
9146
9147 CHECK_ARITY(1);
9148 CAST_TO_STRING;
9149 CHECK_TYPE(XPATH_STRING);
9150 obj = valuePop(ctxt);
9151 source = obj->stringval;
9152
9153 target = xmlBufferCreate();
9154 if (target && source) {
9155
9156 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00009157 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00009158 source++;
9159
9160 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9161 blank = 0;
9162 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00009163 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009164 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00009165 } else {
9166 if (blank) {
9167 xmlBufferAdd(target, &blank, 1);
9168 blank = 0;
9169 }
9170 xmlBufferAdd(target, source, 1);
9171 }
9172 source++;
9173 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009174 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9175 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00009176 xmlBufferFree(target);
9177 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009178 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00009179}
9180
9181/**
9182 * xmlXPathTranslateFunction:
9183 * @ctxt: the XPath Parser context
9184 * @nargs: the number of arguments
9185 *
9186 * Implement the translate() XPath function
9187 * string translate(string, string, string)
9188 * The translate function returns the first argument string with
9189 * occurrences of characters in the second argument string replaced
9190 * by the character at the corresponding position in the third argument
9191 * string. For example, translate("bar","abc","ABC") returns the string
9192 * BAr. If there is a character in the second argument string with no
9193 * character at a corresponding position in the third argument string
9194 * (because the second argument string is longer than the third argument
9195 * string), then occurrences of that character in the first argument
9196 * string are removed. For example, translate("--aaa--","abc-","ABC")
9197 * returns "AAA". If a character occurs more than once in second
9198 * argument string, then the first occurrence determines the replacement
9199 * character. If the third argument string is longer than the second
9200 * argument string, then excess characters are ignored.
9201 */
9202void
9203xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00009204 xmlXPathObjectPtr str;
9205 xmlXPathObjectPtr from;
9206 xmlXPathObjectPtr to;
9207 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009208 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009209 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00009210 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009211 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00009212
Daniel Veillarde043ee12001-04-16 14:08:07 +00009213 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00009214
Daniel Veillarde043ee12001-04-16 14:08:07 +00009215 CAST_TO_STRING;
9216 to = valuePop(ctxt);
9217 CAST_TO_STRING;
9218 from = valuePop(ctxt);
9219 CAST_TO_STRING;
9220 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009221
Daniel Veillarde043ee12001-04-16 14:08:07 +00009222 target = xmlBufferCreate();
9223 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009224 max = xmlUTF8Strlen(to->stringval);
9225 for (cptr = str->stringval; (ch=*cptr); ) {
9226 offset = xmlUTF8Strloc(from->stringval, cptr);
9227 if (offset >= 0) {
9228 if (offset < max) {
9229 point = xmlUTF8Strpos(to->stringval, offset);
9230 if (point)
9231 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
9232 }
9233 } else
9234 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9235
9236 /* Step to next character in input */
9237 cptr++;
9238 if ( ch & 0x80 ) {
9239 /* if not simple ascii, verify proper format */
9240 if ( (ch & 0xc0) != 0xc0 ) {
9241 xmlGenericError(xmlGenericErrorContext,
9242 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9243 break;
9244 }
9245 /* then skip over remaining bytes for this char */
9246 while ( (ch <<= 1) & 0x80 )
9247 if ( (*cptr++ & 0xc0) != 0x80 ) {
9248 xmlGenericError(xmlGenericErrorContext,
9249 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9250 break;
9251 }
9252 if (ch & 0x80) /* must have had error encountered */
9253 break;
9254 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00009255 }
Owen Taylor3473f882001-02-23 17:55:21 +00009256 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009257 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9258 xmlBufferContent(target)));
Daniel Veillarde043ee12001-04-16 14:08:07 +00009259 xmlBufferFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009260 xmlXPathReleaseObject(ctxt->context, str);
9261 xmlXPathReleaseObject(ctxt->context, from);
9262 xmlXPathReleaseObject(ctxt->context, to);
Owen Taylor3473f882001-02-23 17:55:21 +00009263}
9264
9265/**
9266 * xmlXPathBooleanFunction:
9267 * @ctxt: the XPath Parser context
9268 * @nargs: the number of arguments
9269 *
9270 * Implement the boolean() XPath function
9271 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00009272 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00009273 * - a number is true if and only if it is neither positive or
9274 * negative zero nor NaN
9275 * - a node-set is true if and only if it is non-empty
9276 * - a string is true if and only if its length is non-zero
9277 */
9278void
9279xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9280 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00009281
9282 CHECK_ARITY(1);
9283 cur = valuePop(ctxt);
9284 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009285 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009286 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009287}
9288
9289/**
9290 * xmlXPathNotFunction:
9291 * @ctxt: the XPath Parser context
9292 * @nargs: the number of arguments
9293 *
9294 * Implement the not() XPath function
9295 * boolean not(boolean)
9296 * The not function returns true if its argument is false,
9297 * and false otherwise.
9298 */
9299void
9300xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9301 CHECK_ARITY(1);
9302 CAST_TO_BOOLEAN;
9303 CHECK_TYPE(XPATH_BOOLEAN);
9304 ctxt->value->boolval = ! ctxt->value->boolval;
9305}
9306
9307/**
9308 * xmlXPathTrueFunction:
9309 * @ctxt: the XPath Parser context
9310 * @nargs: the number of arguments
9311 *
9312 * Implement the true() XPath function
9313 * boolean true()
9314 */
9315void
9316xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9317 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009318 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009319}
9320
9321/**
9322 * xmlXPathFalseFunction:
9323 * @ctxt: the XPath Parser context
9324 * @nargs: the number of arguments
9325 *
9326 * Implement the false() XPath function
9327 * boolean false()
9328 */
9329void
9330xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9331 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009332 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009333}
9334
9335/**
9336 * xmlXPathLangFunction:
9337 * @ctxt: the XPath Parser context
9338 * @nargs: the number of arguments
9339 *
9340 * Implement the lang() XPath function
9341 * boolean lang(string)
9342 * The lang function returns true or false depending on whether the
9343 * language of the context node as specified by xml:lang attributes
9344 * is the same as or is a sublanguage of the language specified by
9345 * the argument string. The language of the context node is determined
9346 * by the value of the xml:lang attribute on the context node, or, if
9347 * the context node has no xml:lang attribute, by the value of the
9348 * xml:lang attribute on the nearest ancestor of the context node that
9349 * has an xml:lang attribute. If there is no such attribute, then lang
9350 * returns false. If there is such an attribute, then lang returns
9351 * true if the attribute value is equal to the argument ignoring case,
9352 * or if there is some suffix starting with - such that the attribute
9353 * value is equal to the argument ignoring that suffix of the attribute
9354 * value and ignoring case.
9355 */
9356void
9357xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009358 xmlXPathObjectPtr val = NULL;
9359 const xmlChar *theLang = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009360 const xmlChar *lang;
9361 int ret = 0;
9362 int i;
9363
9364 CHECK_ARITY(1);
9365 CAST_TO_STRING;
9366 CHECK_TYPE(XPATH_STRING);
9367 val = valuePop(ctxt);
9368 lang = val->stringval;
9369 theLang = xmlNodeGetLang(ctxt->context->node);
9370 if ((theLang != NULL) && (lang != NULL)) {
9371 for (i = 0;lang[i] != 0;i++)
9372 if (toupper(lang[i]) != toupper(theLang[i]))
9373 goto not_equal;
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009374 if ((theLang[i] == 0) || (theLang[i] == '-'))
9375 ret = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009376 }
9377not_equal:
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009378 if (theLang != NULL)
9379 xmlFree((void *)theLang);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009380
9381 xmlXPathReleaseObject(ctxt->context, val);
9382 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009383}
9384
9385/**
9386 * xmlXPathNumberFunction:
9387 * @ctxt: the XPath Parser context
9388 * @nargs: the number of arguments
9389 *
9390 * Implement the number() XPath function
9391 * number number(object?)
9392 */
9393void
9394xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9395 xmlXPathObjectPtr cur;
9396 double res;
9397
Daniel Veillarda82b1822004-11-08 16:24:57 +00009398 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009399 if (nargs == 0) {
9400 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009401 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
Owen Taylor3473f882001-02-23 17:55:21 +00009402 } else {
9403 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9404
9405 res = xmlXPathStringEvalNumber(content);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009406 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
Owen Taylor3473f882001-02-23 17:55:21 +00009407 xmlFree(content);
9408 }
9409 return;
9410 }
9411
9412 CHECK_ARITY(1);
9413 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009414 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00009415}
9416
9417/**
9418 * xmlXPathSumFunction:
9419 * @ctxt: the XPath Parser context
9420 * @nargs: the number of arguments
9421 *
9422 * Implement the sum() XPath function
9423 * number sum(node-set)
9424 * The sum function returns the sum of the values of the nodes in
9425 * the argument node-set.
9426 */
9427void
9428xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9429 xmlXPathObjectPtr cur;
9430 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009431 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00009432
9433 CHECK_ARITY(1);
9434 if ((ctxt->value == NULL) ||
9435 ((ctxt->value->type != XPATH_NODESET) &&
9436 (ctxt->value->type != XPATH_XSLT_TREE)))
9437 XP_ERROR(XPATH_INVALID_TYPE);
9438 cur = valuePop(ctxt);
9439
William M. Brack08171912003-12-29 02:52:11 +00009440 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009441 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9442 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00009443 }
9444 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009445 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9446 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009447}
9448
William M. Brack3d426662005-04-19 14:40:28 +00009449/*
9450 * To assure working code on multiple platforms, we want to only depend
9451 * upon the characteristic truncation of converting a floating point value
9452 * to an integer. Unfortunately, because of the different storage sizes
9453 * of our internal floating point value (double) and integer (int), we
9454 * can't directly convert (see bug 301162). This macro is a messy
9455 * 'workaround'
9456 */
9457#define XTRUNC(f, v) \
9458 f = fmod((v), INT_MAX); \
9459 f = (v) - (f) + (double)((int)(f));
9460
Owen Taylor3473f882001-02-23 17:55:21 +00009461/**
9462 * xmlXPathFloorFunction:
9463 * @ctxt: the XPath Parser context
9464 * @nargs: the number of arguments
9465 *
9466 * Implement the floor() XPath function
9467 * number floor(number)
9468 * The floor function returns the largest (closest to positive infinity)
9469 * number that is not greater than the argument and that is an integer.
9470 */
9471void
9472xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009473 double f;
9474
Owen Taylor3473f882001-02-23 17:55:21 +00009475 CHECK_ARITY(1);
9476 CAST_TO_NUMBER;
9477 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009478
William M. Brack3d426662005-04-19 14:40:28 +00009479 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009480 if (f != ctxt->value->floatval) {
9481 if (ctxt->value->floatval > 0)
9482 ctxt->value->floatval = f;
9483 else
9484 ctxt->value->floatval = f - 1;
9485 }
Owen Taylor3473f882001-02-23 17:55:21 +00009486}
9487
9488/**
9489 * xmlXPathCeilingFunction:
9490 * @ctxt: the XPath Parser context
9491 * @nargs: the number of arguments
9492 *
9493 * Implement the ceiling() XPath function
9494 * number ceiling(number)
9495 * The ceiling function returns the smallest (closest to negative infinity)
9496 * number that is not less than the argument and that is an integer.
9497 */
9498void
9499xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9500 double f;
9501
9502 CHECK_ARITY(1);
9503 CAST_TO_NUMBER;
9504 CHECK_TYPE(XPATH_NUMBER);
9505
9506#if 0
9507 ctxt->value->floatval = ceil(ctxt->value->floatval);
9508#else
William M. Brack3d426662005-04-19 14:40:28 +00009509 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009510 if (f != ctxt->value->floatval) {
9511 if (ctxt->value->floatval > 0)
9512 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009513 else {
9514 if (ctxt->value->floatval < 0 && f == 0)
9515 ctxt->value->floatval = xmlXPathNZERO;
9516 else
9517 ctxt->value->floatval = f;
9518 }
9519
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009520 }
Owen Taylor3473f882001-02-23 17:55:21 +00009521#endif
9522}
9523
9524/**
9525 * xmlXPathRoundFunction:
9526 * @ctxt: the XPath Parser context
9527 * @nargs: the number of arguments
9528 *
9529 * Implement the round() XPath function
9530 * number round(number)
9531 * The round function returns the number that is closest to the
9532 * argument and that is an integer. If there are two such numbers,
9533 * then the one that is even is returned.
9534 */
9535void
9536xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9537 double f;
9538
9539 CHECK_ARITY(1);
9540 CAST_TO_NUMBER;
9541 CHECK_TYPE(XPATH_NUMBER);
9542
Daniel Veillardcda96922001-08-21 10:56:31 +00009543 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9544 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9545 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009546 (ctxt->value->floatval == 0.0))
9547 return;
9548
William M. Brack3d426662005-04-19 14:40:28 +00009549 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009550 if (ctxt->value->floatval < 0) {
9551 if (ctxt->value->floatval < f - 0.5)
9552 ctxt->value->floatval = f - 1;
9553 else
9554 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009555 if (ctxt->value->floatval == 0)
9556 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009557 } else {
9558 if (ctxt->value->floatval < f + 0.5)
9559 ctxt->value->floatval = f;
9560 else
9561 ctxt->value->floatval = f + 1;
9562 }
Owen Taylor3473f882001-02-23 17:55:21 +00009563}
9564
9565/************************************************************************
9566 * *
9567 * The Parser *
9568 * *
9569 ************************************************************************/
9570
9571/*
William M. Brack08171912003-12-29 02:52:11 +00009572 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00009573 * implementation.
9574 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009575static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009576static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009577static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009578static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00009579static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9580 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00009581
9582/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00009583 * xmlXPathCurrentChar:
9584 * @ctxt: the XPath parser context
9585 * @cur: pointer to the beginning of the char
9586 * @len: pointer to the length of the char read
9587 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009588 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00009589 * bytes in the input buffer.
9590 *
Daniel Veillard60087f32001-10-10 09:45:09 +00009591 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00009592 */
9593
9594static int
9595xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9596 unsigned char c;
9597 unsigned int val;
9598 const xmlChar *cur;
9599
9600 if (ctxt == NULL)
9601 return(0);
9602 cur = ctxt->cur;
9603
9604 /*
9605 * We are supposed to handle UTF8, check it's valid
9606 * From rfc2044: encoding of the Unicode values on UTF-8:
9607 *
9608 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9609 * 0000 0000-0000 007F 0xxxxxxx
9610 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
9611 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
9612 *
9613 * Check for the 0x110000 limit too
9614 */
9615 c = *cur;
9616 if (c & 0x80) {
9617 if ((cur[1] & 0xc0) != 0x80)
9618 goto encoding_error;
9619 if ((c & 0xe0) == 0xe0) {
9620
9621 if ((cur[2] & 0xc0) != 0x80)
9622 goto encoding_error;
9623 if ((c & 0xf0) == 0xf0) {
9624 if (((c & 0xf8) != 0xf0) ||
9625 ((cur[3] & 0xc0) != 0x80))
9626 goto encoding_error;
9627 /* 4-byte code */
9628 *len = 4;
9629 val = (cur[0] & 0x7) << 18;
9630 val |= (cur[1] & 0x3f) << 12;
9631 val |= (cur[2] & 0x3f) << 6;
9632 val |= cur[3] & 0x3f;
9633 } else {
9634 /* 3-byte code */
9635 *len = 3;
9636 val = (cur[0] & 0xf) << 12;
9637 val |= (cur[1] & 0x3f) << 6;
9638 val |= cur[2] & 0x3f;
9639 }
9640 } else {
9641 /* 2-byte code */
9642 *len = 2;
9643 val = (cur[0] & 0x1f) << 6;
9644 val |= cur[1] & 0x3f;
9645 }
9646 if (!IS_CHAR(val)) {
9647 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9648 }
9649 return(val);
9650 } else {
9651 /* 1-byte code */
9652 *len = 1;
9653 return((int) *cur);
9654 }
9655encoding_error:
9656 /*
William M. Brack08171912003-12-29 02:52:11 +00009657 * If we detect an UTF8 error that probably means that the
9658 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00009659 * declaration header. Report the error and switch the encoding
9660 * to ISO-Latin-1 (if you don't like this policy, just declare the
9661 * encoding !)
9662 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00009663 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00009664 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009665}
9666
9667/**
Owen Taylor3473f882001-02-23 17:55:21 +00009668 * xmlXPathParseNCName:
9669 * @ctxt: the XPath Parser context
9670 *
9671 * parse an XML namespace non qualified name.
9672 *
9673 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9674 *
9675 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9676 * CombiningChar | Extender
9677 *
9678 * Returns the namespace name or NULL
9679 */
9680
9681xmlChar *
9682xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00009683 const xmlChar *in;
9684 xmlChar *ret;
9685 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009686
Daniel Veillarda82b1822004-11-08 16:24:57 +00009687 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00009688 /*
9689 * Accelerator for simple ASCII names
9690 */
9691 in = ctxt->cur;
9692 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9693 ((*in >= 0x41) && (*in <= 0x5A)) ||
9694 (*in == '_')) {
9695 in++;
9696 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9697 ((*in >= 0x41) && (*in <= 0x5A)) ||
9698 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00009699 (*in == '_') || (*in == '.') ||
9700 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00009701 in++;
9702 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9703 (*in == '[') || (*in == ']') || (*in == ':') ||
9704 (*in == '@') || (*in == '*')) {
9705 count = in - ctxt->cur;
9706 if (count == 0)
9707 return(NULL);
9708 ret = xmlStrndup(ctxt->cur, count);
9709 ctxt->cur = in;
9710 return(ret);
9711 }
9712 }
9713 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009714}
9715
Daniel Veillard2156a562001-04-28 12:24:34 +00009716
Owen Taylor3473f882001-02-23 17:55:21 +00009717/**
9718 * xmlXPathParseQName:
9719 * @ctxt: the XPath Parser context
9720 * @prefix: a xmlChar **
9721 *
9722 * parse an XML qualified name
9723 *
9724 * [NS 5] QName ::= (Prefix ':')? LocalPart
9725 *
9726 * [NS 6] Prefix ::= NCName
9727 *
9728 * [NS 7] LocalPart ::= NCName
9729 *
9730 * Returns the function returns the local part, and prefix is updated
9731 * to get the Prefix if any.
9732 */
9733
Daniel Veillard56a4cb82001-03-24 17:00:36 +00009734static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00009735xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9736 xmlChar *ret = NULL;
9737
9738 *prefix = NULL;
9739 ret = xmlXPathParseNCName(ctxt);
9740 if (CUR == ':') {
9741 *prefix = ret;
9742 NEXT;
9743 ret = xmlXPathParseNCName(ctxt);
9744 }
9745 return(ret);
9746}
9747
9748/**
9749 * xmlXPathParseName:
9750 * @ctxt: the XPath Parser context
9751 *
9752 * parse an XML name
9753 *
9754 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9755 * CombiningChar | Extender
9756 *
9757 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9758 *
9759 * Returns the namespace name or NULL
9760 */
9761
9762xmlChar *
9763xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009764 const xmlChar *in;
9765 xmlChar *ret;
9766 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009767
Daniel Veillarda82b1822004-11-08 16:24:57 +00009768 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009769 /*
9770 * Accelerator for simple ASCII names
9771 */
9772 in = ctxt->cur;
9773 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9774 ((*in >= 0x41) && (*in <= 0x5A)) ||
9775 (*in == '_') || (*in == ':')) {
9776 in++;
9777 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9778 ((*in >= 0x41) && (*in <= 0x5A)) ||
9779 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00009780 (*in == '_') || (*in == '-') ||
9781 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00009782 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00009783 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009784 count = in - ctxt->cur;
9785 ret = xmlStrndup(ctxt->cur, count);
9786 ctxt->cur = in;
9787 return(ret);
9788 }
9789 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009790 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009791}
9792
Daniel Veillard61d80a22001-04-27 17:13:01 +00009793static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00009794xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009795 xmlChar buf[XML_MAX_NAMELEN + 5];
9796 int len = 0, l;
9797 int c;
9798
9799 /*
9800 * Handler for more complex cases
9801 */
9802 c = CUR_CHAR(l);
9803 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00009804 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9805 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00009806 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00009807 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009808 return(NULL);
9809 }
9810
9811 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9812 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9813 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00009814 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009815 (IS_COMBINING(c)) ||
9816 (IS_EXTENDER(c)))) {
9817 COPY_BUF(l,buf,len,c);
9818 NEXTL(l);
9819 c = CUR_CHAR(l);
9820 if (len >= XML_MAX_NAMELEN) {
9821 /*
9822 * Okay someone managed to make a huge name, so he's ready to pay
9823 * for the processing speed.
9824 */
9825 xmlChar *buffer;
9826 int max = len * 2;
9827
Daniel Veillard3c908dc2003-04-19 00:07:51 +00009828 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009829 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009830 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009831 }
9832 memcpy(buffer, buf, len);
9833 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9834 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00009835 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009836 (IS_COMBINING(c)) ||
9837 (IS_EXTENDER(c))) {
9838 if (len + 10 > max) {
9839 max *= 2;
9840 buffer = (xmlChar *) xmlRealloc(buffer,
9841 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009842 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009843 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009844 }
9845 }
9846 COPY_BUF(l,buffer,len,c);
9847 NEXTL(l);
9848 c = CUR_CHAR(l);
9849 }
9850 buffer[len] = 0;
9851 return(buffer);
9852 }
9853 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009854 if (len == 0)
9855 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009856 return(xmlStrndup(buf, len));
9857}
Daniel Veillard3cd72402002-05-13 10:33:30 +00009858
9859#define MAX_FRAC 20
9860
William M. Brack372a4452004-02-17 13:09:23 +00009861/*
9862 * These are used as divisors for the fractional part of a number.
9863 * Since the table includes 1.0 (representing '0' fractional digits),
9864 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
9865 */
9866static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +00009867 1.0, 10.0, 100.0, 1000.0, 10000.0,
9868 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
9869 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
9870 100000000000000.0,
9871 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +00009872 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +00009873};
9874
Owen Taylor3473f882001-02-23 17:55:21 +00009875/**
9876 * xmlXPathStringEvalNumber:
9877 * @str: A string to scan
9878 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00009879 * [30a] Float ::= Number ('e' Digits?)?
9880 *
Owen Taylor3473f882001-02-23 17:55:21 +00009881 * [30] Number ::= Digits ('.' Digits?)?
9882 * | '.' Digits
9883 * [31] Digits ::= [0-9]+
9884 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009885 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00009886 * In complement of the Number expression, this function also handles
9887 * negative values : '-' Number.
9888 *
9889 * Returns the double value.
9890 */
9891double
9892xmlXPathStringEvalNumber(const xmlChar *str) {
9893 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00009894 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009895 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009896 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009897 int exponent = 0;
9898 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009899#ifdef __GNUC__
9900 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00009901 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009902#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00009903 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00009904 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009905 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
9906 return(xmlXPathNAN);
9907 }
9908 if (*cur == '-') {
9909 isneg = 1;
9910 cur++;
9911 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00009912
9913#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009914 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00009915 * tmp/temp is a workaround against a gcc compiler bug
9916 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009917 */
Daniel Veillard7b416132002-03-07 08:36:03 +00009918 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009919 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00009920 ret = ret * 10;
9921 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00009922 ok = 1;
9923 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00009924 temp = (double) tmp;
9925 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00009926 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00009927#else
Daniel Veillard7b416132002-03-07 08:36:03 +00009928 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009929 while ((*cur >= '0') && (*cur <= '9')) {
9930 ret = ret * 10 + (*cur - '0');
9931 ok = 1;
9932 cur++;
9933 }
9934#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009935
Owen Taylor3473f882001-02-23 17:55:21 +00009936 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00009937 int v, frac = 0;
9938 double fraction = 0;
9939
Owen Taylor3473f882001-02-23 17:55:21 +00009940 cur++;
9941 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
9942 return(xmlXPathNAN);
9943 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00009944 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
9945 v = (*cur - '0');
9946 fraction = fraction * 10 + v;
9947 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009948 cur++;
9949 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00009950 fraction /= my_pow10[frac];
9951 ret = ret + fraction;
9952 while ((*cur >= '0') && (*cur <= '9'))
9953 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009954 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00009955 if ((*cur == 'e') || (*cur == 'E')) {
9956 cur++;
9957 if (*cur == '-') {
9958 is_exponent_negative = 1;
9959 cur++;
William M. Brack99127052004-05-24 02:52:28 +00009960 } else if (*cur == '+') {
9961 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009962 }
9963 while ((*cur >= '0') && (*cur <= '9')) {
9964 exponent = exponent * 10 + (*cur - '0');
9965 cur++;
9966 }
9967 }
William M. Brack76e95df2003-10-18 16:20:14 +00009968 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009969 if (*cur != 0) return(xmlXPathNAN);
9970 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009971 if (is_exponent_negative) exponent = -exponent;
9972 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00009973 return(ret);
9974}
9975
9976/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009977 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00009978 * @ctxt: the XPath Parser context
9979 *
9980 * [30] Number ::= Digits ('.' Digits?)?
9981 * | '.' Digits
9982 * [31] Digits ::= [0-9]+
9983 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009984 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00009985 *
9986 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009987static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009988xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
9989{
Owen Taylor3473f882001-02-23 17:55:21 +00009990 double ret = 0.0;
9991 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00009992 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009993 int exponent = 0;
9994 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00009995#ifdef __GNUC__
9996 unsigned long tmp = 0;
9997 double temp;
9998#endif
Owen Taylor3473f882001-02-23 17:55:21 +00009999
10000 CHECK_ERROR;
10001 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10002 XP_ERROR(XPATH_NUMBER_ERROR);
10003 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010004#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010005 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010006 * tmp/temp is a workaround against a gcc compiler bug
10007 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010008 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010009 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010010 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010011 ret = ret * 10;
10012 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010013 ok = 1;
10014 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +000010015 temp = (double) tmp;
10016 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010017 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010018#else
10019 ret = 0;
10020 while ((CUR >= '0') && (CUR <= '9')) {
10021 ret = ret * 10 + (CUR - '0');
10022 ok = 1;
10023 NEXT;
10024 }
10025#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010026 if (CUR == '.') {
10027 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010028 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10029 XP_ERROR(XPATH_NUMBER_ERROR);
10030 }
10031 while ((CUR >= '0') && (CUR <= '9')) {
10032 mult /= 10;
10033 ret = ret + (CUR - '0') * mult;
10034 NEXT;
10035 }
Owen Taylor3473f882001-02-23 17:55:21 +000010036 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010037 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010038 NEXT;
10039 if (CUR == '-') {
10040 is_exponent_negative = 1;
10041 NEXT;
William M. Brack99127052004-05-24 02:52:28 +000010042 } else if (CUR == '+') {
10043 NEXT;
10044 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010045 while ((CUR >= '0') && (CUR <= '9')) {
10046 exponent = exponent * 10 + (CUR - '0');
10047 NEXT;
10048 }
10049 if (is_exponent_negative)
10050 exponent = -exponent;
10051 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +000010052 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010053 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010054 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010055}
10056
10057/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010058 * xmlXPathParseLiteral:
10059 * @ctxt: the XPath Parser context
10060 *
10061 * Parse a Literal
10062 *
10063 * [29] Literal ::= '"' [^"]* '"'
10064 * | "'" [^']* "'"
10065 *
10066 * Returns the value found or NULL in case of error
10067 */
10068static xmlChar *
10069xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10070 const xmlChar *q;
10071 xmlChar *ret = NULL;
10072
10073 if (CUR == '"') {
10074 NEXT;
10075 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010076 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010077 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010078 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010079 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010080 } else {
10081 ret = xmlStrndup(q, CUR_PTR - q);
10082 NEXT;
10083 }
10084 } else if (CUR == '\'') {
10085 NEXT;
10086 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010087 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010088 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010089 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010090 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010091 } else {
10092 ret = xmlStrndup(q, CUR_PTR - q);
10093 NEXT;
10094 }
10095 } else {
Daniel Veillard24505b02005-07-28 23:49:35 +000010096 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010097 }
10098 return(ret);
10099}
10100
10101/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010102 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +000010103 * @ctxt: the XPath Parser context
10104 *
10105 * Parse a Literal and push it on the stack.
10106 *
10107 * [29] Literal ::= '"' [^"]* '"'
10108 * | "'" [^']* "'"
10109 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010110 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +000010111 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010112static void
10113xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010114 const xmlChar *q;
10115 xmlChar *ret = NULL;
10116
10117 if (CUR == '"') {
10118 NEXT;
10119 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010120 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +000010121 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010122 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010123 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10124 } else {
10125 ret = xmlStrndup(q, CUR_PTR - q);
10126 NEXT;
10127 }
10128 } else if (CUR == '\'') {
10129 NEXT;
10130 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010131 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +000010132 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010133 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010134 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10135 } else {
10136 ret = xmlStrndup(q, CUR_PTR - q);
10137 NEXT;
10138 }
10139 } else {
10140 XP_ERROR(XPATH_START_LITERAL_ERROR);
10141 }
10142 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010143 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010144 xmlXPathCacheNewString(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010145 xmlFree(ret);
10146}
10147
10148/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010149 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +000010150 * @ctxt: the XPath Parser context
10151 *
10152 * Parse a VariableReference, evaluate it and push it on the stack.
10153 *
10154 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +000010155 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +000010156 * of any of the types that are possible for the value of an expression,
10157 * and may also be of additional types not specified here.
10158 *
10159 * Early evaluation is possible since:
10160 * The variable bindings [...] used to evaluate a subexpression are
10161 * always the same as those used to evaluate the containing expression.
10162 *
10163 * [36] VariableReference ::= '$' QName
10164 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010165static void
10166xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010167 xmlChar *name;
10168 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010169
10170 SKIP_BLANKS;
10171 if (CUR != '$') {
10172 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10173 }
10174 NEXT;
10175 name = xmlXPathParseQName(ctxt, &prefix);
10176 if (name == NULL) {
10177 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10178 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010179 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010180 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10181 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010182 SKIP_BLANKS;
Daniel Veillardb3d14912005-09-04 20:47:39 +000010183 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10184 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
10185 }
Owen Taylor3473f882001-02-23 17:55:21 +000010186}
10187
10188/**
10189 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +000010190 * @name: a name string
10191 *
10192 * Is the name given a NodeType one.
10193 *
10194 * [38] NodeType ::= 'comment'
10195 * | 'text'
10196 * | 'processing-instruction'
10197 * | 'node'
10198 *
10199 * Returns 1 if true 0 otherwise
10200 */
10201int
10202xmlXPathIsNodeType(const xmlChar *name) {
10203 if (name == NULL)
10204 return(0);
10205
Daniel Veillard1971ee22002-01-31 20:29:19 +000010206 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +000010207 return(1);
10208 if (xmlStrEqual(name, BAD_CAST "text"))
10209 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010210 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +000010211 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010212 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +000010213 return(1);
10214 return(0);
10215}
10216
10217/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010218 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +000010219 * @ctxt: the XPath Parser context
10220 *
10221 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10222 * [17] Argument ::= Expr
10223 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010224 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +000010225 * pushed on the stack
10226 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010227static void
10228xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010229 xmlChar *name;
10230 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010231 int nbargs = 0;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010232 int sort = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010233
10234 name = xmlXPathParseQName(ctxt, &prefix);
10235 if (name == NULL) {
10236 XP_ERROR(XPATH_EXPR_ERROR);
10237 }
10238 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010239#ifdef DEBUG_EXPR
10240 if (prefix == NULL)
10241 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10242 name);
10243 else
10244 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10245 prefix, name);
10246#endif
10247
Owen Taylor3473f882001-02-23 17:55:21 +000010248 if (CUR != '(') {
10249 XP_ERROR(XPATH_EXPR_ERROR);
10250 }
10251 NEXT;
10252 SKIP_BLANKS;
10253
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010254 /*
10255 * Optimization for count(): we don't need the node-set to be sorted.
10256 */
10257 if ((prefix == NULL) && (name[0] == 'c') &&
10258 xmlStrEqual(name, BAD_CAST "count"))
10259 {
10260 sort = 0;
10261 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010262 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +000010263 if (CUR != ')') {
10264 while (CUR != 0) {
10265 int op1 = ctxt->comp->last;
10266 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010267 xmlXPathCompileExpr(ctxt, sort);
Daniel Veillard71f9d732003-01-14 16:07:16 +000010268 CHECK_ERROR;
10269 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10270 nbargs++;
10271 if (CUR == ')') break;
10272 if (CUR != ',') {
10273 XP_ERROR(XPATH_EXPR_ERROR);
10274 }
10275 NEXT;
10276 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010277 }
Owen Taylor3473f882001-02-23 17:55:21 +000010278 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010279 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10280 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010281 NEXT;
10282 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010283}
10284
10285/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010286 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010287 * @ctxt: the XPath Parser context
10288 *
10289 * [15] PrimaryExpr ::= VariableReference
10290 * | '(' Expr ')'
10291 * | Literal
10292 * | Number
10293 * | FunctionCall
10294 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010295 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010296 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010297static void
10298xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010299 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010300 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010301 else if (CUR == '(') {
10302 NEXT;
10303 SKIP_BLANKS;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010304 xmlXPathCompileExpr(ctxt, 1);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010305 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000010306 if (CUR != ')') {
10307 XP_ERROR(XPATH_EXPR_ERROR);
10308 }
10309 NEXT;
10310 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010311 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010312 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010313 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010314 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010315 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010316 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010317 }
10318 SKIP_BLANKS;
10319}
10320
10321/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010322 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010323 * @ctxt: the XPath Parser context
10324 *
10325 * [20] FilterExpr ::= PrimaryExpr
10326 * | FilterExpr Predicate
10327 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010328 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010329 * Square brackets are used to filter expressions in the same way that
10330 * they are used in location paths. It is an error if the expression to
10331 * be filtered does not evaluate to a node-set. The context node list
10332 * used for evaluating the expression in square brackets is the node-set
10333 * to be filtered listed in document order.
10334 */
10335
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010336static void
10337xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10338 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010339 CHECK_ERROR;
10340 SKIP_BLANKS;
10341
10342 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010343 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +000010344 SKIP_BLANKS;
10345 }
10346
10347
10348}
10349
10350/**
10351 * xmlXPathScanName:
10352 * @ctxt: the XPath Parser context
10353 *
10354 * Trickery: parse an XML name but without consuming the input flow
10355 * Needed to avoid insanity in the parser state.
10356 *
10357 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10358 * CombiningChar | Extender
10359 *
10360 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10361 *
10362 * [6] Names ::= Name (S Name)*
10363 *
10364 * Returns the Name parsed or NULL
10365 */
10366
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010367static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +000010368xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +000010369 int len = 0, l;
10370 int c;
Daniel Veillard03226812004-11-01 14:55:21 +000010371 const xmlChar *cur;
10372 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +000010373
Daniel Veillard03226812004-11-01 14:55:21 +000010374 cur = ctxt->cur;
10375
10376 c = CUR_CHAR(l);
10377 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10378 (!IS_LETTER(c) && (c != '_') &&
10379 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010380 return(NULL);
10381 }
10382
Daniel Veillard03226812004-11-01 14:55:21 +000010383 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10384 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10385 (c == '.') || (c == '-') ||
10386 (c == '_') || (c == ':') ||
10387 (IS_COMBINING(c)) ||
10388 (IS_EXTENDER(c)))) {
10389 len += l;
10390 NEXTL(l);
10391 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +000010392 }
Daniel Veillard03226812004-11-01 14:55:21 +000010393 ret = xmlStrndup(cur, ctxt->cur - cur);
10394 ctxt->cur = cur;
10395 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +000010396}
10397
10398/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010399 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010400 * @ctxt: the XPath Parser context
10401 *
10402 * [19] PathExpr ::= LocationPath
10403 * | FilterExpr
10404 * | FilterExpr '/' RelativeLocationPath
10405 * | FilterExpr '//' RelativeLocationPath
10406 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010407 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010408 * The / operator and // operators combine an arbitrary expression
10409 * and a relative location path. It is an error if the expression
10410 * does not evaluate to a node-set.
10411 * The / operator does composition in the same way as when / is
10412 * used in a location path. As in location paths, // is short for
10413 * /descendant-or-self::node()/.
10414 */
10415
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010416static void
10417xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010418 int lc = 1; /* Should we branch to LocationPath ? */
10419 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10420
10421 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010422 if ((CUR == '$') || (CUR == '(') ||
10423 (IS_ASCII_DIGIT(CUR)) ||
10424 (CUR == '\'') || (CUR == '"') ||
10425 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010426 lc = 0;
10427 } else if (CUR == '*') {
10428 /* relative or absolute location path */
10429 lc = 1;
10430 } else if (CUR == '/') {
10431 /* relative or absolute location path */
10432 lc = 1;
10433 } else if (CUR == '@') {
10434 /* relative abbreviated attribute location path */
10435 lc = 1;
10436 } else if (CUR == '.') {
10437 /* relative abbreviated attribute location path */
10438 lc = 1;
10439 } else {
10440 /*
10441 * Problem is finding if we have a name here whether it's:
10442 * - a nodetype
10443 * - a function call in which case it's followed by '('
10444 * - an axis in which case it's followed by ':'
10445 * - a element name
10446 * We do an a priori analysis here rather than having to
10447 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +000010448 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +000010449 * read/write/debug.
10450 */
10451 SKIP_BLANKS;
10452 name = xmlXPathScanName(ctxt);
10453 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10454#ifdef DEBUG_STEP
10455 xmlGenericError(xmlGenericErrorContext,
10456 "PathExpr: Axis\n");
10457#endif
10458 lc = 1;
10459 xmlFree(name);
10460 } else if (name != NULL) {
10461 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +000010462
10463
10464 while (NXT(len) != 0) {
10465 if (NXT(len) == '/') {
10466 /* element name */
10467#ifdef DEBUG_STEP
10468 xmlGenericError(xmlGenericErrorContext,
10469 "PathExpr: AbbrRelLocation\n");
10470#endif
10471 lc = 1;
10472 break;
William M. Brack76e95df2003-10-18 16:20:14 +000010473 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +000010474 /* ignore blanks */
10475 ;
Owen Taylor3473f882001-02-23 17:55:21 +000010476 } else if (NXT(len) == ':') {
10477#ifdef DEBUG_STEP
10478 xmlGenericError(xmlGenericErrorContext,
10479 "PathExpr: AbbrRelLocation\n");
10480#endif
10481 lc = 1;
10482 break;
10483 } else if ((NXT(len) == '(')) {
10484 /* Note Type or Function */
10485 if (xmlXPathIsNodeType(name)) {
10486#ifdef DEBUG_STEP
10487 xmlGenericError(xmlGenericErrorContext,
10488 "PathExpr: Type search\n");
10489#endif
10490 lc = 1;
10491 } else {
10492#ifdef DEBUG_STEP
10493 xmlGenericError(xmlGenericErrorContext,
10494 "PathExpr: function call\n");
10495#endif
10496 lc = 0;
10497 }
10498 break;
10499 } else if ((NXT(len) == '[')) {
10500 /* element name */
10501#ifdef DEBUG_STEP
10502 xmlGenericError(xmlGenericErrorContext,
10503 "PathExpr: AbbrRelLocation\n");
10504#endif
10505 lc = 1;
10506 break;
10507 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10508 (NXT(len) == '=')) {
10509 lc = 1;
10510 break;
10511 } else {
10512 lc = 1;
10513 break;
10514 }
10515 len++;
10516 }
10517 if (NXT(len) == 0) {
10518#ifdef DEBUG_STEP
10519 xmlGenericError(xmlGenericErrorContext,
10520 "PathExpr: AbbrRelLocation\n");
10521#endif
10522 /* element name */
10523 lc = 1;
10524 }
10525 xmlFree(name);
10526 } else {
William M. Brack08171912003-12-29 02:52:11 +000010527 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +000010528 XP_ERROR(XPATH_EXPR_ERROR);
10529 }
10530 }
10531
10532 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010533 if (CUR == '/') {
10534 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10535 } else {
10536 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010537 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010538 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010539 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010540 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010541 CHECK_ERROR;
10542 if ((CUR == '/') && (NXT(1) == '/')) {
10543 SKIP(2);
10544 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010545
10546 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10547 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10548 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10549
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010550 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010551 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010552 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010553 }
10554 }
10555 SKIP_BLANKS;
10556}
10557
10558/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010559 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010560 * @ctxt: the XPath Parser context
10561 *
10562 * [18] UnionExpr ::= PathExpr
10563 * | UnionExpr '|' PathExpr
10564 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010565 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010566 */
10567
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010568static void
10569xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10570 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010571 CHECK_ERROR;
10572 SKIP_BLANKS;
10573 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010574 int op1 = ctxt->comp->last;
10575 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010576
10577 NEXT;
10578 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010579 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010580
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010581 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10582
Owen Taylor3473f882001-02-23 17:55:21 +000010583 SKIP_BLANKS;
10584 }
Owen Taylor3473f882001-02-23 17:55:21 +000010585}
10586
10587/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010588 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010589 * @ctxt: the XPath Parser context
10590 *
10591 * [27] UnaryExpr ::= UnionExpr
10592 * | '-' UnaryExpr
10593 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010594 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010595 */
10596
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010597static void
10598xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010599 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010600 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010601
10602 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +000010603 while (CUR == '-') {
10604 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010605 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010606 NEXT;
10607 SKIP_BLANKS;
10608 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010609
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010610 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010611 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010612 if (found) {
10613 if (minus)
10614 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10615 else
10616 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010617 }
10618}
10619
10620/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010621 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010622 * @ctxt: the XPath Parser context
10623 *
10624 * [26] MultiplicativeExpr ::= UnaryExpr
10625 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10626 * | MultiplicativeExpr 'div' UnaryExpr
10627 * | MultiplicativeExpr 'mod' UnaryExpr
10628 * [34] MultiplyOperator ::= '*'
10629 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010630 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010631 */
10632
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010633static void
10634xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10635 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010636 CHECK_ERROR;
10637 SKIP_BLANKS;
10638 while ((CUR == '*') ||
10639 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10640 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10641 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010642 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010643
10644 if (CUR == '*') {
10645 op = 0;
10646 NEXT;
10647 } else if (CUR == 'd') {
10648 op = 1;
10649 SKIP(3);
10650 } else if (CUR == 'm') {
10651 op = 2;
10652 SKIP(3);
10653 }
10654 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010655 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010656 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010657 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010658 SKIP_BLANKS;
10659 }
10660}
10661
10662/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010663 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010664 * @ctxt: the XPath Parser context
10665 *
10666 * [25] AdditiveExpr ::= MultiplicativeExpr
10667 * | AdditiveExpr '+' MultiplicativeExpr
10668 * | AdditiveExpr '-' MultiplicativeExpr
10669 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010670 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010671 */
10672
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010673static void
10674xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010675
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010676 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010677 CHECK_ERROR;
10678 SKIP_BLANKS;
10679 while ((CUR == '+') || (CUR == '-')) {
10680 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010681 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010682
10683 if (CUR == '+') plus = 1;
10684 else plus = 0;
10685 NEXT;
10686 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010687 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010688 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010689 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010690 SKIP_BLANKS;
10691 }
10692}
10693
10694/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010695 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010696 * @ctxt: the XPath Parser context
10697 *
10698 * [24] RelationalExpr ::= AdditiveExpr
10699 * | RelationalExpr '<' AdditiveExpr
10700 * | RelationalExpr '>' AdditiveExpr
10701 * | RelationalExpr '<=' AdditiveExpr
10702 * | RelationalExpr '>=' AdditiveExpr
10703 *
10704 * A <= B > C is allowed ? Answer from James, yes with
10705 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10706 * which is basically what got implemented.
10707 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010708 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +000010709 * on the stack
10710 */
10711
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010712static void
10713xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10714 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010715 CHECK_ERROR;
10716 SKIP_BLANKS;
10717 while ((CUR == '<') ||
10718 (CUR == '>') ||
10719 ((CUR == '<') && (NXT(1) == '=')) ||
10720 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010721 int inf, strict;
10722 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010723
10724 if (CUR == '<') inf = 1;
10725 else inf = 0;
10726 if (NXT(1) == '=') strict = 0;
10727 else strict = 1;
10728 NEXT;
10729 if (!strict) NEXT;
10730 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010731 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010732 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010733 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +000010734 SKIP_BLANKS;
10735 }
10736}
10737
10738/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010739 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010740 * @ctxt: the XPath Parser context
10741 *
10742 * [23] EqualityExpr ::= RelationalExpr
10743 * | EqualityExpr '=' RelationalExpr
10744 * | EqualityExpr '!=' RelationalExpr
10745 *
10746 * A != B != C is allowed ? Answer from James, yes with
10747 * (RelationalExpr = RelationalExpr) = RelationalExpr
10748 * (RelationalExpr != RelationalExpr) != RelationalExpr
10749 * which is basically what got implemented.
10750 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010751 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010752 *
10753 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010754static void
10755xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10756 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010757 CHECK_ERROR;
10758 SKIP_BLANKS;
10759 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010760 int eq;
10761 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010762
10763 if (CUR == '=') eq = 1;
10764 else eq = 0;
10765 NEXT;
10766 if (!eq) NEXT;
10767 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010768 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010769 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010770 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010771 SKIP_BLANKS;
10772 }
10773}
10774
10775/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010776 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010777 * @ctxt: the XPath Parser context
10778 *
10779 * [22] AndExpr ::= EqualityExpr
10780 * | AndExpr 'and' EqualityExpr
10781 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010782 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010783 *
10784 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010785static void
10786xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10787 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010788 CHECK_ERROR;
10789 SKIP_BLANKS;
10790 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010791 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010792 SKIP(3);
10793 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010794 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010795 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010796 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010797 SKIP_BLANKS;
10798 }
10799}
10800
10801/**
Daniel Veillard591b4be2003-02-09 23:33:36 +000010802 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010803 * @ctxt: the XPath Parser context
10804 *
10805 * [14] Expr ::= OrExpr
10806 * [21] OrExpr ::= AndExpr
10807 * | OrExpr 'or' AndExpr
10808 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010809 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +000010810 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010811static void
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010812xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010813 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010814 CHECK_ERROR;
10815 SKIP_BLANKS;
10816 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010817 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010818 SKIP(2);
10819 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010820 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010821 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010822 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10823 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +000010824 SKIP_BLANKS;
10825 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010826 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010827 /* more ops could be optimized too */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010828 /*
10829 * This is the main place to eliminate sorting for
10830 * operations which don't require a sorted node-set.
10831 * E.g. count().
10832 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010833 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10834 }
Owen Taylor3473f882001-02-23 17:55:21 +000010835}
10836
10837/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010838 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +000010839 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010840 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +000010841 *
10842 * [8] Predicate ::= '[' PredicateExpr ']'
10843 * [9] PredicateExpr ::= Expr
10844 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010845 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +000010846 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010847static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010848xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010849 int op1 = ctxt->comp->last;
10850
10851 SKIP_BLANKS;
10852 if (CUR != '[') {
10853 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10854 }
10855 NEXT;
10856 SKIP_BLANKS;
10857
10858 ctxt->comp->last = -1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000010859 /*
10860 * This call to xmlXPathCompileExpr() will deactivate sorting
10861 * of the predicate result.
10862 * TODO: Sorting is still activated for filters, since I'm not
10863 * sure if needed. Normally sorting should not be needed, since
10864 * a filter can only diminish the number of items in a sequence,
10865 * but won't change its order; so if the initial sequence is sorted,
10866 * subsequent sorting is not needed.
10867 */
10868 if (! filter)
10869 xmlXPathCompileExpr(ctxt, 0);
10870 else
10871 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010872 CHECK_ERROR;
10873
10874 if (CUR != ']') {
10875 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10876 }
10877
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010878 if (filter)
10879 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10880 else
10881 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010882
10883 NEXT;
10884 SKIP_BLANKS;
10885}
10886
10887/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010888 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +000010889 * @ctxt: the XPath Parser context
10890 * @test: pointer to a xmlXPathTestVal
10891 * @type: pointer to a xmlXPathTypeVal
10892 * @prefix: placeholder for a possible name prefix
10893 *
10894 * [7] NodeTest ::= NameTest
10895 * | NodeType '(' ')'
10896 * | 'processing-instruction' '(' Literal ')'
10897 *
10898 * [37] NameTest ::= '*'
10899 * | NCName ':' '*'
10900 * | QName
10901 * [38] NodeType ::= 'comment'
10902 * | 'text'
10903 * | 'processing-instruction'
10904 * | 'node'
10905 *
William M. Brack08171912003-12-29 02:52:11 +000010906 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +000010907 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010908static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010909xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10910 xmlXPathTypeVal *type, const xmlChar **prefix,
10911 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +000010912 int blanks;
10913
10914 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10915 STRANGE;
10916 return(NULL);
10917 }
William M. Brack78637da2003-07-31 14:47:38 +000010918 *type = (xmlXPathTypeVal) 0;
10919 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010920 *prefix = NULL;
10921 SKIP_BLANKS;
10922
10923 if ((name == NULL) && (CUR == '*')) {
10924 /*
10925 * All elements
10926 */
10927 NEXT;
10928 *test = NODE_TEST_ALL;
10929 return(NULL);
10930 }
10931
10932 if (name == NULL)
10933 name = xmlXPathParseNCName(ctxt);
10934 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010935 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010936 }
10937
William M. Brack76e95df2003-10-18 16:20:14 +000010938 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +000010939 SKIP_BLANKS;
10940 if (CUR == '(') {
10941 NEXT;
10942 /*
10943 * NodeType or PI search
10944 */
10945 if (xmlStrEqual(name, BAD_CAST "comment"))
10946 *type = NODE_TYPE_COMMENT;
10947 else if (xmlStrEqual(name, BAD_CAST "node"))
10948 *type = NODE_TYPE_NODE;
10949 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10950 *type = NODE_TYPE_PI;
10951 else if (xmlStrEqual(name, BAD_CAST "text"))
10952 *type = NODE_TYPE_TEXT;
10953 else {
10954 if (name != NULL)
10955 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000010956 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010957 }
10958
10959 *test = NODE_TEST_TYPE;
10960
10961 SKIP_BLANKS;
10962 if (*type == NODE_TYPE_PI) {
10963 /*
10964 * Specific case: search a PI by name.
10965 */
Owen Taylor3473f882001-02-23 17:55:21 +000010966 if (name != NULL)
10967 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +000010968 name = NULL;
10969 if (CUR != ')') {
10970 name = xmlXPathParseLiteral(ctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000010971 CHECK_ERROR NULL;
Daniel Veillarded23b7d2002-05-27 12:16:02 +000010972 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +000010973 SKIP_BLANKS;
10974 }
Owen Taylor3473f882001-02-23 17:55:21 +000010975 }
10976 if (CUR != ')') {
10977 if (name != NULL)
10978 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000010979 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010980 }
10981 NEXT;
10982 return(name);
10983 }
10984 *test = NODE_TEST_NAME;
10985 if ((!blanks) && (CUR == ':')) {
10986 NEXT;
10987
10988 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010989 * Since currently the parser context don't have a
10990 * namespace list associated:
10991 * The namespace name for this prefix can be computed
10992 * only at evaluation time. The compilation is done
10993 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +000010994 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010995#if 0
Owen Taylor3473f882001-02-23 17:55:21 +000010996 *prefix = xmlXPathNsLookup(ctxt->context, name);
10997 if (name != NULL)
10998 xmlFree(name);
10999 if (*prefix == NULL) {
11000 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11001 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011002#else
11003 *prefix = name;
11004#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011005
11006 if (CUR == '*') {
11007 /*
11008 * All elements
11009 */
11010 NEXT;
11011 *test = NODE_TEST_ALL;
11012 return(NULL);
11013 }
11014
11015 name = xmlXPathParseNCName(ctxt);
11016 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011017 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011018 }
11019 }
11020 return(name);
11021}
11022
11023/**
11024 * xmlXPathIsAxisName:
11025 * @name: a preparsed name token
11026 *
11027 * [6] AxisName ::= 'ancestor'
11028 * | 'ancestor-or-self'
11029 * | 'attribute'
11030 * | 'child'
11031 * | 'descendant'
11032 * | 'descendant-or-self'
11033 * | 'following'
11034 * | 'following-sibling'
11035 * | 'namespace'
11036 * | 'parent'
11037 * | 'preceding'
11038 * | 'preceding-sibling'
11039 * | 'self'
11040 *
11041 * Returns the axis or 0
11042 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011043static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +000011044xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +000011045 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011046 switch (name[0]) {
11047 case 'a':
11048 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11049 ret = AXIS_ANCESTOR;
11050 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11051 ret = AXIS_ANCESTOR_OR_SELF;
11052 if (xmlStrEqual(name, BAD_CAST "attribute"))
11053 ret = AXIS_ATTRIBUTE;
11054 break;
11055 case 'c':
11056 if (xmlStrEqual(name, BAD_CAST "child"))
11057 ret = AXIS_CHILD;
11058 break;
11059 case 'd':
11060 if (xmlStrEqual(name, BAD_CAST "descendant"))
11061 ret = AXIS_DESCENDANT;
11062 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11063 ret = AXIS_DESCENDANT_OR_SELF;
11064 break;
11065 case 'f':
11066 if (xmlStrEqual(name, BAD_CAST "following"))
11067 ret = AXIS_FOLLOWING;
11068 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11069 ret = AXIS_FOLLOWING_SIBLING;
11070 break;
11071 case 'n':
11072 if (xmlStrEqual(name, BAD_CAST "namespace"))
11073 ret = AXIS_NAMESPACE;
11074 break;
11075 case 'p':
11076 if (xmlStrEqual(name, BAD_CAST "parent"))
11077 ret = AXIS_PARENT;
11078 if (xmlStrEqual(name, BAD_CAST "preceding"))
11079 ret = AXIS_PRECEDING;
11080 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11081 ret = AXIS_PRECEDING_SIBLING;
11082 break;
11083 case 's':
11084 if (xmlStrEqual(name, BAD_CAST "self"))
11085 ret = AXIS_SELF;
11086 break;
11087 }
11088 return(ret);
11089}
11090
11091/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011092 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +000011093 * @ctxt: the XPath Parser context
11094 *
11095 * [4] Step ::= AxisSpecifier NodeTest Predicate*
11096 * | AbbreviatedStep
11097 *
11098 * [12] AbbreviatedStep ::= '.' | '..'
11099 *
11100 * [5] AxisSpecifier ::= AxisName '::'
11101 * | AbbreviatedAxisSpecifier
11102 *
11103 * [13] AbbreviatedAxisSpecifier ::= '@'?
11104 *
11105 * Modified for XPtr range support as:
11106 *
11107 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11108 * | AbbreviatedStep
11109 * | 'range-to' '(' Expr ')' Predicate*
11110 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011111 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +000011112 * A location step of . is short for self::node(). This is
11113 * particularly useful in conjunction with //. For example, the
11114 * location path .//para is short for
11115 * self::node()/descendant-or-self::node()/child::para
11116 * and so will select all para descendant elements of the context
11117 * node.
11118 * Similarly, a location step of .. is short for parent::node().
11119 * For example, ../title is short for parent::node()/child::title
11120 * and so will select the title children of the parent of the context
11121 * node.
11122 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011123static void
11124xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011125#ifdef LIBXML_XPTR_ENABLED
11126 int rangeto = 0;
11127 int op2 = -1;
11128#endif
11129
Owen Taylor3473f882001-02-23 17:55:21 +000011130 SKIP_BLANKS;
11131 if ((CUR == '.') && (NXT(1) == '.')) {
11132 SKIP(2);
11133 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011134 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11135 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011136 } else if (CUR == '.') {
11137 NEXT;
11138 SKIP_BLANKS;
11139 } else {
11140 xmlChar *name = NULL;
11141 const xmlChar *prefix = NULL;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011142 xmlXPathTestVal test = (xmlXPathTestVal) 0;
William M. Brack78637da2003-07-31 14:47:38 +000011143 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011144 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011145 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +000011146
11147 /*
11148 * The modification needed for XPointer change to the production
11149 */
11150#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011151 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +000011152 name = xmlXPathParseNCName(ctxt);
11153 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011154 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011155 xmlFree(name);
11156 SKIP_BLANKS;
11157 if (CUR != '(') {
11158 XP_ERROR(XPATH_EXPR_ERROR);
11159 }
11160 NEXT;
11161 SKIP_BLANKS;
11162
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011163 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011164 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +000011165 CHECK_ERROR;
11166
11167 SKIP_BLANKS;
11168 if (CUR != ')') {
11169 XP_ERROR(XPATH_EXPR_ERROR);
11170 }
11171 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011172 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000011173 goto eval_predicates;
11174 }
11175 }
11176#endif
Daniel Veillard2156a562001-04-28 12:24:34 +000011177 if (CUR == '*') {
11178 axis = AXIS_CHILD;
11179 } else {
11180 if (name == NULL)
11181 name = xmlXPathParseNCName(ctxt);
11182 if (name != NULL) {
11183 axis = xmlXPathIsAxisName(name);
11184 if (axis != 0) {
11185 SKIP_BLANKS;
11186 if ((CUR == ':') && (NXT(1) == ':')) {
11187 SKIP(2);
11188 xmlFree(name);
11189 name = NULL;
11190 } else {
11191 /* an element name can conflict with an axis one :-\ */
11192 axis = AXIS_CHILD;
11193 }
Owen Taylor3473f882001-02-23 17:55:21 +000011194 } else {
Owen Taylor3473f882001-02-23 17:55:21 +000011195 axis = AXIS_CHILD;
11196 }
Daniel Veillard2156a562001-04-28 12:24:34 +000011197 } else if (CUR == '@') {
11198 NEXT;
11199 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +000011200 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +000011201 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +000011202 }
Owen Taylor3473f882001-02-23 17:55:21 +000011203 }
11204
11205 CHECK_ERROR;
11206
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011207 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +000011208 if (test == 0)
11209 return;
11210
Daniel Veillarded6c5492005-07-23 15:00:22 +000011211 if ((prefix != NULL) && (ctxt->context != NULL) &&
11212 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11213 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11214 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11215 }
11216 }
Owen Taylor3473f882001-02-23 17:55:21 +000011217#ifdef DEBUG_STEP
11218 xmlGenericError(xmlGenericErrorContext,
11219 "Basis : computing new set\n");
11220#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011221
Owen Taylor3473f882001-02-23 17:55:21 +000011222#ifdef DEBUG_STEP
11223 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011224 if (ctxt->value == NULL)
11225 xmlGenericError(xmlGenericErrorContext, "no value\n");
11226 else if (ctxt->value->nodesetval == NULL)
11227 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11228 else
11229 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011230#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011231
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011232#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +000011233eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011234#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011235 op1 = ctxt->comp->last;
11236 ctxt->comp->last = -1;
11237
Owen Taylor3473f882001-02-23 17:55:21 +000011238 SKIP_BLANKS;
11239 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011240 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011241 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011242
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011243#ifdef LIBXML_XPTR_ENABLED
11244 if (rangeto) {
11245 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11246 } else
11247#endif
11248 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11249 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011250
Owen Taylor3473f882001-02-23 17:55:21 +000011251 }
11252#ifdef DEBUG_STEP
11253 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011254 if (ctxt->value == NULL)
11255 xmlGenericError(xmlGenericErrorContext, "no value\n");
11256 else if (ctxt->value->nodesetval == NULL)
11257 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11258 else
11259 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11260 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011261#endif
11262}
11263
11264/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011265 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011266 * @ctxt: the XPath Parser context
11267 *
11268 * [3] RelativeLocationPath ::= Step
11269 * | RelativeLocationPath '/' Step
11270 * | AbbreviatedRelativeLocationPath
11271 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
11272 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011273 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +000011274 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011275static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011276xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011277(xmlXPathParserContextPtr ctxt) {
11278 SKIP_BLANKS;
11279 if ((CUR == '/') && (NXT(1) == '/')) {
11280 SKIP(2);
11281 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011282 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11283 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011284 } else if (CUR == '/') {
11285 NEXT;
11286 SKIP_BLANKS;
11287 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011288 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011289 SKIP_BLANKS;
11290 while (CUR == '/') {
11291 if ((CUR == '/') && (NXT(1) == '/')) {
11292 SKIP(2);
11293 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011294 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +000011295 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011296 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011297 } else if (CUR == '/') {
11298 NEXT;
11299 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011300 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011301 }
11302 SKIP_BLANKS;
11303 }
11304}
11305
11306/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011307 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011308 * @ctxt: the XPath Parser context
11309 *
11310 * [1] LocationPath ::= RelativeLocationPath
11311 * | AbsoluteLocationPath
11312 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
11313 * | AbbreviatedAbsoluteLocationPath
11314 * [10] AbbreviatedAbsoluteLocationPath ::=
11315 * '//' RelativeLocationPath
11316 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011317 * Compile a location path
11318 *
Owen Taylor3473f882001-02-23 17:55:21 +000011319 * // is short for /descendant-or-self::node()/. For example,
11320 * //para is short for /descendant-or-self::node()/child::para and
11321 * so will select any para element in the document (even a para element
11322 * that is a document element will be selected by //para since the
11323 * document element node is a child of the root node); div//para is
11324 * short for div/descendant-or-self::node()/child::para and so will
11325 * select all para descendants of div children.
11326 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011327static void
11328xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000011329 SKIP_BLANKS;
11330 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011331 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011332 } else {
11333 while (CUR == '/') {
11334 if ((CUR == '/') && (NXT(1) == '/')) {
11335 SKIP(2);
11336 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011337 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11338 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011339 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011340 } else if (CUR == '/') {
11341 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +000011342 SKIP_BLANKS;
11343 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +000011344 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +000011345 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011346 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011347 }
11348 }
11349 }
11350}
11351
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011352/************************************************************************
11353 * *
11354 * XPath precompiled expression evaluation *
11355 * *
11356 ************************************************************************/
11357
Daniel Veillardf06307e2001-07-03 10:35:50 +000011358static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011359xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11360
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011361#ifdef DEBUG_STEP
11362static void
11363xmlXPathDebugDumpStepAxis(xmlXPathAxisVal axis,
11364 xmlXPathTestVal test,
11365 int nbNodes)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011366{
Daniel Veillardf06307e2001-07-03 10:35:50 +000011367 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011368 switch (axis) {
11369 case AXIS_ANCESTOR:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011370 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011371 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011372 case AXIS_ANCESTOR_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011373 xmlGenericError(xmlGenericErrorContext,
11374 "axis 'ancestors-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011375 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011376 case AXIS_ATTRIBUTE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011377 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011378 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011379 case AXIS_CHILD:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011380 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011381 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011382 case AXIS_DESCENDANT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011383 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011384 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011385 case AXIS_DESCENDANT_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011386 xmlGenericError(xmlGenericErrorContext,
11387 "axis 'descendant-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011388 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011389 case AXIS_FOLLOWING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011390 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011391 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011392 case AXIS_FOLLOWING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011393 xmlGenericError(xmlGenericErrorContext,
11394 "axis 'following-siblings' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011395 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011396 case AXIS_NAMESPACE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011397 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011398 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011399 case AXIS_PARENT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011400 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011401 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011402 case AXIS_PRECEDING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011403 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011404 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011405 case AXIS_PRECEDING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011406 xmlGenericError(xmlGenericErrorContext,
11407 "axis 'preceding-sibling' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011408 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011409 case AXIS_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011410 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011411 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011412 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011413 xmlGenericError(xmlGenericErrorContext,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011414 " context contains %d nodes\n", nbNodes);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011415 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011416 case NODE_TEST_NONE:
11417 xmlGenericError(xmlGenericErrorContext,
11418 " searching for none !!!\n");
11419 break;
11420 case NODE_TEST_TYPE:
11421 xmlGenericError(xmlGenericErrorContext,
11422 " searching for type %d\n", type);
11423 break;
11424 case NODE_TEST_PI:
11425 xmlGenericError(xmlGenericErrorContext,
11426 " searching for PI !!!\n");
11427 break;
11428 case NODE_TEST_ALL:
11429 xmlGenericError(xmlGenericErrorContext,
11430 " searching for *\n");
11431 break;
11432 case NODE_TEST_NS:
11433 xmlGenericError(xmlGenericErrorContext,
11434 " searching for namespace %s\n",
11435 prefix);
11436 break;
11437 case NODE_TEST_NAME:
11438 xmlGenericError(xmlGenericErrorContext,
11439 " searching for name %s\n", name);
11440 if (prefix != NULL)
11441 xmlGenericError(xmlGenericErrorContext,
11442 " with namespace %s\n", prefix);
11443 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011444 }
11445 xmlGenericError(xmlGenericErrorContext, "Testing : ");
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011446}
11447#endif /* DEBUG_STEP */
11448
11449static int
11450xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11451 xmlXPathStepOpPtr op,
11452 xmlNodeSetPtr set,
11453 int contextSize,
11454 int hasNsNodes)
11455{
11456 if (op->ch1 != -1) {
11457 xmlXPathCompExprPtr comp = ctxt->comp;
11458 /*
11459 * Process inner predicates first.
11460 */
11461 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11462 /*
11463 * TODO: raise an internal error.
11464 */
11465 }
11466 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11467 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11468 CHECK_ERROR0;
11469 if (contextSize <= 0)
11470 return(0);
11471 }
11472 if (op->ch2 != -1) {
11473 xmlXPathContextPtr xpctxt = ctxt->context;
11474 xmlNodePtr contextNode, oldContextNode;
11475 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011476 int i, res, contextPos = 0, newContextSize;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011477 xmlXPathStepOpPtr exprOp;
11478 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11479
11480#ifdef LIBXML_XPTR_ENABLED
11481 /*
11482 * URGENT TODO: Check the following:
11483 * We don't expect location sets if evaluating prediates, right?
11484 * Only filters should expect location sets, right?
11485 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011486#endif
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011487 /*
11488 * SPEC XPath 1.0:
11489 * "For each node in the node-set to be filtered, the
11490 * PredicateExpr is evaluated with that node as the
11491 * context node, with the number of nodes in the
11492 * node-set as the context size, and with the proximity
11493 * position of the node in the node-set with respect to
11494 * the axis as the context position;"
11495 * @oldset is the node-set" to be filtered.
11496 *
11497 * SPEC XPath 1.0:
11498 * "only predicates change the context position and
11499 * context size (see [2.4 Predicates])."
11500 * Example:
11501 * node-set context pos
11502 * nA 1
11503 * nB 2
11504 * nC 3
11505 * After applying predicate [position() > 1] :
11506 * node-set context pos
11507 * nB 1
11508 * nC 2
11509 */
11510 oldContextNode = xpctxt->node;
11511 oldContextDoc = xpctxt->doc;
11512 /*
11513 * Get the expression of this predicate.
11514 */
11515 exprOp = &ctxt->comp->steps[op->ch2];
11516 newContextSize = 0;
11517 for (i = 0; i < set->nodeNr; i++) {
11518 if (set->nodeTab[i] == NULL)
11519 continue;
11520
11521 contextNode = set->nodeTab[i];
11522 xpctxt->node = contextNode;
11523 xpctxt->contextSize = contextSize;
11524 xpctxt->proximityPosition = ++contextPos;
11525
11526 /*
11527 * Also set the xpath document in case things like
11528 * key() are evaluated in the predicate.
11529 */
11530 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11531 (contextNode->doc != NULL))
11532 xpctxt->doc = contextNode->doc;
11533 /*
11534 * Evaluate the predicate expression with 1 context node
11535 * at a time; this node is packaged into a node set; this
11536 * node set is handed over to the evaluation mechanism.
11537 */
11538 if (contextObj == NULL)
11539 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11540 else
11541 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11542 contextNode);
11543
11544 valuePush(ctxt, contextObj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011545
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011546 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011547
11548 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1))
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011549 goto evaluation_error;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011550
11551 if (res != 0) {
11552 newContextSize++;
11553 } else {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011554 /*
11555 * Remove the entry from the initial node set.
11556 */
11557 set->nodeTab[i] = NULL;
11558 if (contextNode->type == XML_NAMESPACE_DECL)
11559 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011560 }
11561 if (ctxt->value == contextObj) {
11562 /*
11563 * Don't free the temporary XPath object holding the
11564 * context node, in order to avoid massive recreation
11565 * inside this loop.
11566 */
11567 valuePop(ctxt);
11568 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11569 } else {
11570 /*
11571 * TODO: The object was lost in the evaluation machinery.
11572 * Can this happen? Maybe in internal-error cases.
11573 */
11574 contextObj = NULL;
11575 }
11576 }
11577 goto evaluation_exit;
11578
11579evaluation_error:
11580 xmlXPathNodeSetClear(set, hasNsNodes);
11581 newContextSize = 0;
11582
11583evaluation_exit:
11584 if (contextObj != NULL) {
11585 if (ctxt->value == contextObj)
11586 valuePop(ctxt);
11587 xmlXPathReleaseObject(xpctxt, contextObj);
11588 }
11589 if (exprRes != NULL)
11590 xmlXPathReleaseObject(ctxt->context, exprRes);
11591 /*
11592 * Reset/invalidate the context.
11593 */
11594 xpctxt->node = oldContextNode;
11595 xpctxt->doc = oldContextDoc;
11596 xpctxt->contextSize = -1;
11597 xpctxt->proximityPosition = -1;
11598 return(newContextSize);
11599 }
11600 return(contextSize);
11601}
11602
11603static int
11604xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11605 xmlXPathStepOpPtr op,
11606 xmlNodeSetPtr set,
11607 int contextSize,
11608 int minPos,
11609 int maxPos,
11610 int hasNsNodes)
11611{
11612 if (op->ch1 != -1) {
11613 xmlXPathCompExprPtr comp = ctxt->comp;
11614 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11615 /*
11616 * TODO: raise an internal error.
11617 */
11618 }
11619 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11620 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11621 CHECK_ERROR0;
11622 if (contextSize <= 0)
11623 return(0);
11624 }
11625 /*
11626 * Check if the node set contains a sufficient number of nodes for
11627 * the requested range.
11628 */
11629 if (contextSize < minPos) {
11630 xmlXPathNodeSetClear(set, hasNsNodes);
11631 return(0);
11632 }
11633 if (op->ch2 == -1) {
11634 /*
11635 * TODO: Can this ever happen?
11636 */
11637 return (contextSize);
11638 } else {
11639 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011640 int i, pos = 0, newContextSize = 0, contextPos = 0, res;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011641 xmlXPathStepOpPtr exprOp;
11642 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11643 xmlNodePtr oldContextNode, contextNode = NULL;
11644 xmlXPathContextPtr xpctxt = ctxt->context;
11645
11646#ifdef LIBXML_XPTR_ENABLED
11647 /*
11648 * URGENT TODO: Check the following:
11649 * We don't expect location sets if evaluating prediates, right?
11650 * Only filters should expect location sets, right?
11651 */
11652#endif /* LIBXML_XPTR_ENABLED */
11653
11654 /*
11655 * Save old context.
11656 */
11657 oldContextNode = xpctxt->node;
11658 oldContextDoc = xpctxt->doc;
11659 /*
11660 * Get the expression of this predicate.
11661 */
11662 exprOp = &ctxt->comp->steps[op->ch2];
11663 for (i = 0; i < set->nodeNr; i++) {
11664 if (set->nodeTab[i] == NULL)
11665 continue;
11666
11667 contextNode = set->nodeTab[i];
11668 xpctxt->node = contextNode;
11669 xpctxt->contextSize = contextSize;
11670 xpctxt->proximityPosition = ++contextPos;
11671
11672 /*
11673 * Initialize the new set.
11674 * Also set the xpath document in case things like
11675 * key() evaluation are attempted on the predicate
11676 */
11677 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11678 (contextNode->doc != NULL))
11679 xpctxt->doc = contextNode->doc;
11680 /*
11681 * Evaluate the predicate expression with 1 context node
11682 * at a time; this node is packaged into a node set; this
11683 * node set is handed over to the evaluation mechanism.
11684 */
11685 if (contextObj == NULL)
11686 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11687 else
11688 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11689 contextNode);
11690
11691 valuePush(ctxt, contextObj);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011692 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011693
11694 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1))
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011695 goto evaluation_error;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011696
11697 if (res)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011698 pos++;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011699
11700 if (res && (pos >= minPos) && (pos <= maxPos)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011701 /*
11702 * Fits in the requested range.
11703 */
11704 newContextSize++;
11705 if (minPos == maxPos) {
11706 /*
11707 * Only 1 node was requested.
11708 */
11709 if (contextNode->type == XML_NAMESPACE_DECL) {
11710 /*
11711 * As always: take care of those nasty
11712 * namespace nodes.
11713 */
11714 set->nodeTab[i] = NULL;
11715 }
11716 xmlXPathNodeSetClear(set, hasNsNodes);
11717 set->nodeNr = 1;
11718 set->nodeTab[0] = contextNode;
11719 goto evaluation_exit;
11720 }
11721 if (pos == maxPos) {
11722 /*
11723 * We are done.
11724 */
11725 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11726 goto evaluation_exit;
11727 }
11728 } else {
11729 /*
11730 * Remove the entry from the initial node set.
11731 */
11732 set->nodeTab[i] = NULL;
11733 if (contextNode->type == XML_NAMESPACE_DECL)
11734 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11735 }
11736 if (exprRes != NULL) {
11737 xmlXPathReleaseObject(ctxt->context, exprRes);
11738 exprRes = NULL;
11739 }
11740 if (ctxt->value == contextObj) {
11741 /*
11742 * Don't free the temporary XPath object holding the
11743 * context node, in order to avoid massive recreation
11744 * inside this loop.
11745 */
11746 valuePop(ctxt);
11747 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11748 } else {
11749 /*
11750 * The object was lost in the evaluation machinery.
11751 * Can this happen? Maybe in case of internal-errors.
11752 */
11753 contextObj = NULL;
11754 }
11755 }
11756 goto evaluation_exit;
11757
11758evaluation_error:
11759 xmlXPathNodeSetClear(set, hasNsNodes);
11760 newContextSize = 0;
11761
11762evaluation_exit:
11763 if (contextObj != NULL) {
11764 if (ctxt->value == contextObj)
11765 valuePop(ctxt);
11766 xmlXPathReleaseObject(xpctxt, contextObj);
11767 }
11768 if (exprRes != NULL)
11769 xmlXPathReleaseObject(ctxt->context, exprRes);
11770 /*
11771 * Reset/invalidate the context.
11772 */
11773 xpctxt->node = oldContextNode;
11774 xpctxt->doc = oldContextDoc;
11775 xpctxt->contextSize = -1;
11776 xpctxt->proximityPosition = -1;
11777 return(newContextSize);
11778 }
11779 return(contextSize);
11780}
11781
11782static int
11783xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11784 xmlXPathStepOpPtr op,
11785 int *maxPos)
11786{
11787
11788 xmlXPathStepOpPtr exprOp;
11789
11790 /*
11791 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11792 */
11793
11794 /*
11795 * If not -1, then ch1 will point to:
11796 * 1) For predicates (XPATH_OP_PREDICATE):
11797 * - an inner predicate operator
11798 * 2) For filters (XPATH_OP_FILTER):
11799 * - an inner filter operater OR
11800 * - an expression selecting the node set.
11801 * E.g. "key('a', 'b')" or "(//foo | //bar)".
11802 */
11803 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11804 return(0);
11805
11806 if (op->ch2 != -1) {
11807 exprOp = &ctxt->comp->steps[op->ch2];
11808 } else
11809 return(0);
11810
11811 if ((exprOp != NULL) &&
11812 (exprOp->op == XPATH_OP_VALUE) &&
11813 (exprOp->value4 != NULL) &&
11814 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11815 {
11816 /*
11817 * We have a "[n]" predicate here.
11818 * TODO: Unfortunately this simplistic test here is not
11819 * able to detect a position() predicate in compound
11820 * expressions like "[@attr = 'a" and position() = 1],
11821 * and even not the usage of position() in
11822 * "[position() = 1]"; thus - obviously - a position-range,
11823 * like it "[position() < 5]", is also not detected.
11824 * Maybe we could rewrite the AST to ease the optimization.
11825 */
11826 *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11827
11828 if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
11829 (float) *maxPos)
11830 {
11831 return(1);
11832 }
11833 }
11834 return(0);
11835}
11836
11837static int
11838xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11839 xmlXPathStepOpPtr op,
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011840 xmlNodePtr * first, xmlNodePtr * last,
11841 int toBool)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011842{
11843
11844#define XP_TEST_HIT \
11845 if (hasAxisRange != 0) { \
11846 if (++pos == maxPos) { \
11847 addNode(seq, cur); \
11848 goto axis_range_end; } \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011849 } else { \
11850 addNode(seq, cur); \
11851 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011852
11853#define XP_TEST_HIT_NS \
11854 if (hasAxisRange != 0) { \
11855 if (++pos == maxPos) { \
11856 hasNsNodes = 1; \
11857 xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
11858 goto axis_range_end; } \
11859 } else { \
11860 hasNsNodes = 1; \
11861 xmlXPathNodeSetAddNs(seq, \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011862 xpctxt->node, (xmlNsPtr) cur); \
11863 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011864
11865 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11866 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11867 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11868 const xmlChar *prefix = op->value4;
11869 const xmlChar *name = op->value5;
11870 const xmlChar *URI = NULL;
11871
11872#ifdef DEBUG_STEP
11873 int nbMatches = 0, prevMatches = 0;
11874#endif
11875 int total = 0, hasNsNodes = 0;
11876 /* The popped object holding the context nodes */
11877 xmlXPathObjectPtr obj;
11878 /* The set of context nodes for the node tests */
11879 xmlNodeSetPtr contextSeq;
11880 int contextIdx;
11881 xmlNodePtr contextNode;
11882 /* The context node for a compound traversal */
11883 xmlNodePtr outerContextNode;
11884 /* The final resulting node set wrt to all context nodes */
11885 xmlNodeSetPtr outSeq;
11886 /*
11887 * The temporary resulting node set wrt 1 context node.
11888 * Used to feed predicate evaluation.
11889 */
11890 xmlNodeSetPtr seq;
11891 xmlNodePtr cur;
11892 /* First predicate operator */
11893 xmlXPathStepOpPtr predOp;
11894 int maxPos; /* The requested position() (when a "[n]" predicate) */
11895 int hasPredicateRange, hasAxisRange, pos, size, newSize;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011896 int breakOnFirstHit;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011897
11898 xmlXPathTraversalFunction next = NULL;
11899 /* compound axis traversal */
11900 xmlXPathTraversalFunctionExt outerNext = NULL;
11901 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
11902 xmlXPathNodeSetMergeFunction mergeAndClear;
11903 xmlNodePtr oldContextNode;
11904 xmlXPathContextPtr xpctxt = ctxt->context;
11905
11906
11907 CHECK_TYPE0(XPATH_NODESET);
11908 obj = valuePop(ctxt);
11909 /*
11910 * Setup namespaces.
11911 */
11912 if (prefix != NULL) {
11913 URI = xmlXPathNsLookup(xpctxt, prefix);
11914 if (URI == NULL) {
11915 xmlXPathReleaseObject(xpctxt, obj);
11916 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11917 }
11918 }
11919 /*
11920 * Setup axis.
11921 *
11922 * MAYBE FUTURE TODO: merging optimizations:
11923 * - If the nodes to be traversed wrt to the initial nodes and
11924 * the current axis cannot overlap, then we could avoid searching
11925 * for duplicates during the merge.
11926 * But the question is how/when to evaluate if they cannot overlap.
11927 * Example: if we know that for two initial nodes, the one is
11928 * not in the ancestor-or-self axis of the other, then we could safely
11929 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
11930 * the descendant-or-self axis.
11931 */
11932 addNode = xmlXPathNodeSetAdd;
11933 mergeAndClear = xmlXPathNodeSetMergeAndClear;
11934 switch (axis) {
11935 case AXIS_ANCESTOR:
11936 first = NULL;
11937 next = xmlXPathNextAncestor;
11938 break;
11939 case AXIS_ANCESTOR_OR_SELF:
11940 first = NULL;
11941 next = xmlXPathNextAncestorOrSelf;
11942 break;
11943 case AXIS_ATTRIBUTE:
11944 first = NULL;
11945 last = NULL;
11946 next = xmlXPathNextAttribute;
11947 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11948 break;
11949 case AXIS_CHILD:
11950 last = NULL;
11951 if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
11952 /*
11953 * This iterator will give us only nodes which can
11954 * hold element nodes.
11955 */
11956 outerNext = xmlXPathNextDescendantOrSelfElemParent;
11957 }
11958 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
11959 (type == NODE_TYPE_NODE))
11960 {
11961 /*
11962 * Optimization if an element node type is 'element'.
11963 */
11964 next = xmlXPathNextChildElement;
11965 } else
11966 next = xmlXPathNextChild;
11967 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11968 break;
11969 case AXIS_DESCENDANT:
11970 last = NULL;
11971 next = xmlXPathNextDescendant;
11972 break;
11973 case AXIS_DESCENDANT_OR_SELF:
11974 last = NULL;
11975 next = xmlXPathNextDescendantOrSelf;
11976 break;
11977 case AXIS_FOLLOWING:
11978 last = NULL;
11979 next = xmlXPathNextFollowing;
11980 break;
11981 case AXIS_FOLLOWING_SIBLING:
11982 last = NULL;
11983 next = xmlXPathNextFollowingSibling;
11984 break;
11985 case AXIS_NAMESPACE:
11986 first = NULL;
11987 last = NULL;
11988 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
11989 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11990 break;
11991 case AXIS_PARENT:
11992 first = NULL;
11993 next = xmlXPathNextParent;
11994 break;
11995 case AXIS_PRECEDING:
11996 first = NULL;
11997 next = xmlXPathNextPrecedingInternal;
11998 break;
11999 case AXIS_PRECEDING_SIBLING:
12000 first = NULL;
12001 next = xmlXPathNextPrecedingSibling;
12002 break;
12003 case AXIS_SELF:
12004 first = NULL;
12005 last = NULL;
12006 next = xmlXPathNextSelf;
12007 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12008 break;
12009 }
12010
12011#ifdef DEBUG_STEP
12012 xmlXPathDebugDumpStepAxis(axis, test,
12013 (obj->nodesetval != NULL) ? obj->nodsetval->nodeNr : 0);
12014#endif
12015
12016 if (next == NULL) {
12017 xmlXPathReleaseObject(xpctxt, obj);
12018 return(0);
12019 }
12020 contextSeq = obj->nodesetval;
12021 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12022 xmlXPathReleaseObject(xpctxt, obj);
12023 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12024 return(0);
12025 }
12026 /*
12027 * Predicate optimization ---------------------------------------------
12028 * If this step has a last predicate, which contains a position(),
12029 * then we'll optimize (although not exactly "position()", but only
12030 * the short-hand form, i.e., "[n]".
12031 *
12032 * Example - expression "/foo[parent::bar][1]":
12033 *
12034 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12035 * ROOT -- op->ch1
12036 * PREDICATE -- op->ch2 (predOp)
12037 * PREDICATE -- predOp->ch1 = [parent::bar]
12038 * SORT
12039 * COLLECT 'parent' 'name' 'node' bar
12040 * NODE
12041 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12042 *
12043 */
12044 maxPos = 0;
12045 predOp = NULL;
12046 hasPredicateRange = 0;
12047 hasAxisRange = 0;
12048 if (op->ch2 != -1) {
12049 /*
12050 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12051 */
12052 predOp = &ctxt->comp->steps[op->ch2];
12053 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12054 if (predOp->ch1 != -1) {
12055 /*
12056 * Use the next inner predicate operator.
12057 */
12058 predOp = &ctxt->comp->steps[predOp->ch1];
12059 hasPredicateRange = 1;
12060 } else {
12061 /*
12062 * There's no other predicate than the [n] predicate.
12063 */
12064 predOp = NULL;
12065 hasAxisRange = 1;
12066 }
12067 }
12068 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012069 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012070 /*
12071 * Axis traversal -----------------------------------------------------
12072 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012073 /*
12074 * 2.3 Node Tests
12075 * - For the attribute axis, the principal node type is attribute.
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012076 * - For the namespace axis, the principal node type is namespace.
12077 * - For other axes, the principal node type is element.
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012078 *
12079 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012080 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012081 * select all element children of the context node
12082 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012083 oldContextNode = xpctxt->node;
12084 addNode = xmlXPathNodeSetAddUnique;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012085 outSeq = NULL;
12086 seq = NULL;
12087 outerContextNode = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012088 contextNode = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012089 contextIdx = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012090
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012091
12092 while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
12093 if (outerNext != NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012094 /*
12095 * This is a compound traversal.
12096 */
12097 if (contextNode == NULL) {
12098 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012099 * Set the context for the outer traversal.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012100 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012101 outerContextNode = contextSeq->nodeTab[contextIdx++];
12102 contextNode = outerNext(NULL, outerContextNode);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012103 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012104 contextNode = outerNext(contextNode, outerContextNode);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012105 if (contextNode == NULL)
12106 continue;
12107 /*
12108 * Set the context for the main traversal.
12109 */
12110 xpctxt->node = contextNode;
12111 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012112 xpctxt->node = contextSeq->nodeTab[contextIdx++];
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012113
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012114 if (seq == NULL) {
12115 seq = xmlXPathNodeSetCreate(NULL);
12116 if (seq == NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012117 total = 0;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012118 goto error;
12119 }
12120 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012121 /*
12122 * Traverse the axis and test the nodes.
12123 */
12124 pos = 0;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012125 cur = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012126 hasNsNodes = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012127 do {
12128 cur = next(ctxt, cur);
12129 if (cur == NULL)
12130 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012131
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012132 /*
12133 * QUESTION TODO: What does the "first" and "last" stuff do?
12134 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012135 if ((first != NULL) && (*first != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012136 if (*first == cur)
12137 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012138 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012139#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012140 (xmlXPathCmpNodesExt(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012141#else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012142 (xmlXPathCmpNodes(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012143#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012144 {
12145 break;
12146 }
12147 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012148 if ((last != NULL) && (*last != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012149 if (*last == cur)
12150 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012151 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012152#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012153 (xmlXPathCmpNodesExt(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012154#else
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012155 (xmlXPathCmpNodes(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012156#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012157 {
12158 break;
12159 }
12160 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012161
12162 total++;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012163
Daniel Veillardf06307e2001-07-03 10:35:50 +000012164#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012165 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12166#endif
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012167 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012168 case NODE_TEST_NONE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012169 total = 0;
12170 STRANGE
12171 goto error;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012172 case NODE_TEST_TYPE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012173 /*
12174 * TODO: Don't we need to use
12175 * xmlXPathNodeSetAddNs() for namespace nodes here?
12176 * Surprisingly, some c14n tests fail, if we do this.
12177 */
12178 if (type == NODE_TYPE_NODE) {
12179 switch (cur->type) {
12180 case XML_DOCUMENT_NODE:
12181 case XML_HTML_DOCUMENT_NODE:
12182#ifdef LIBXML_DOCB_ENABLED
12183 case XML_DOCB_DOCUMENT_NODE:
12184#endif
12185 case XML_ELEMENT_NODE:
12186 case XML_ATTRIBUTE_NODE:
12187 case XML_PI_NODE:
12188 case XML_COMMENT_NODE:
12189 case XML_CDATA_SECTION_NODE:
12190 case XML_TEXT_NODE:
12191 case XML_NAMESPACE_DECL:
12192 XP_TEST_HIT
12193 break;
12194 default:
12195 break;
12196 }
12197 } else if (cur->type == type) {
Kasimier T. Buchcik889b7622006-07-03 11:44:13 +000012198 if (type == XML_NAMESPACE_DECL)
12199 XP_TEST_HIT_NS
12200 else
12201 XP_TEST_HIT
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012202 } else if ((type == NODE_TYPE_TEXT) &&
12203 (cur->type == XML_CDATA_SECTION_NODE))
12204 {
12205 XP_TEST_HIT
12206 }
12207 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012208 case NODE_TEST_PI:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012209 if ((cur->type == XML_PI_NODE) &&
12210 ((name == NULL) || xmlStrEqual(name, cur->name)))
12211 {
12212 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012213 }
12214 break;
12215 case NODE_TEST_ALL:
12216 if (axis == AXIS_ATTRIBUTE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012217 if (cur->type == XML_ATTRIBUTE_NODE)
12218 {
12219 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012220 }
12221 } else if (axis == AXIS_NAMESPACE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012222 if (cur->type == XML_NAMESPACE_DECL)
12223 {
12224 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012225 }
12226 } else {
12227 if (cur->type == XML_ELEMENT_NODE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012228 if (prefix == NULL)
12229 {
12230 XP_TEST_HIT
12231
Daniel Veillardf06307e2001-07-03 10:35:50 +000012232 } else if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012233 (xmlStrEqual(URI, cur->ns->href)))
12234 {
12235 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012236 }
12237 }
12238 }
12239 break;
12240 case NODE_TEST_NS:{
12241 TODO;
12242 break;
12243 }
12244 case NODE_TEST_NAME:
12245 switch (cur->type) {
12246 case XML_ELEMENT_NODE:
12247 if (xmlStrEqual(name, cur->name)) {
12248 if (prefix == NULL) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012249 if (cur->ns == NULL)
12250 {
12251 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012252 }
12253 } else {
12254 if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012255 (xmlStrEqual(URI, cur->ns->href)))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012256 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012257 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012258 }
12259 }
12260 }
12261 break;
12262 case XML_ATTRIBUTE_NODE:{
12263 xmlAttrPtr attr = (xmlAttrPtr) cur;
12264
12265 if (xmlStrEqual(name, attr->name)) {
12266 if (prefix == NULL) {
12267 if ((attr->ns == NULL) ||
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012268 (attr->ns->prefix == NULL))
12269 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012270 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012271 }
12272 } else {
12273 if ((attr->ns != NULL) &&
12274 (xmlStrEqual(URI,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012275 attr->ns->href)))
12276 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012277 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012278 }
12279 }
12280 }
12281 break;
12282 }
12283 case XML_NAMESPACE_DECL:
12284 if (cur->type == XML_NAMESPACE_DECL) {
12285 xmlNsPtr ns = (xmlNsPtr) cur;
12286
12287 if ((ns->prefix != NULL) && (name != NULL)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012288 && (xmlStrEqual(ns->prefix, name)))
12289 {
12290 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012291 }
12292 }
12293 break;
12294 default:
12295 break;
12296 }
12297 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012298 } /* switch(test) */
12299 } while (cur != NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012300
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012301 goto apply_predicates;
12302
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012303axis_range_end: /* ----------------------------------------------------- */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012304 /*
12305 * We have a "/foo[n]", and position() = n was reached.
12306 * Note that we can have as well "/foo/::parent::foo[1]", so
12307 * a duplicate-aware merge is still needed.
12308 * Merge with the result.
12309 */
12310 if (outSeq == NULL) {
12311 outSeq = seq;
12312 seq = NULL;
12313 } else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012314 outSeq = mergeAndClear(outSeq, seq, 0);
12315 /*
12316 * Break if only a true/false result was requested.
12317 */
12318 if (toBool)
12319 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012320 continue;
12321
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012322first_hit: /* ---------------------------------------------------------- */
12323 /*
12324 * Break if only a true/false result was requested and
12325 * no predicates existed and a node test succeeded.
12326 */
12327 if (outSeq == NULL) {
12328 outSeq = seq;
12329 seq = NULL;
12330 } else
12331 outSeq = mergeAndClear(outSeq, seq, 0);
12332 break;
12333
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012334#ifdef DEBUG_STEP
12335 if (seq != NULL)
12336 nbMatches += seq->nodeNr;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012337#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012338
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012339apply_predicates: /* --------------------------------------------------- */
12340 /*
12341 * Apply predicates.
12342 */
12343 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12344 /*
12345 * E.g. when we have a "/foo[some expression][n]".
12346 */
12347 /*
12348 * QUESTION TODO: The old predicate evaluation took into
12349 * account location-sets.
12350 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12351 * Do we expect such a set here?
12352 * All what I learned now from the evaluation semantics
12353 * does not indicate that a location-set will be processed
12354 * here, so this looks OK.
12355 */
12356 /*
12357 * Iterate over all predicates, starting with the outermost
12358 * predicate.
12359 * TODO: Problem: we cannot execute the inner predicates first
12360 * since we cannot go back *up* the operator tree!
12361 * Options we have:
12362 * 1) Use of recursive functions (like is it currently done
12363 * via xmlXPathCompOpEval())
12364 * 2) Add a predicate evaluation information stack to the
12365 * context struct
12366 * 3) Change the way the operators are linked; we need a
12367 * "parent" field on xmlXPathStepOp
12368 *
12369 * For the moment, I'll try to solve this with a recursive
12370 * function: xmlXPathCompOpEvalPredicate().
12371 */
12372 size = seq->nodeNr;
12373 if (hasPredicateRange != 0)
12374 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12375 predOp, seq, size, maxPos, maxPos, hasNsNodes);
12376 else
12377 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12378 predOp, seq, size, hasNsNodes);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012379
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012380 if (ctxt->error != XPATH_EXPRESSION_OK) {
12381 total = 0;
12382 goto error;
12383 }
12384 /*
12385 * Add the filtered set of nodes to the result node set.
12386 */
12387 if (newSize == 0) {
12388 /*
12389 * The predicates filtered all nodes out.
12390 */
12391 xmlXPathNodeSetClear(seq, hasNsNodes);
12392 } else if (seq->nodeNr > 0) {
12393 /*
12394 * Add to result set.
12395 */
12396 if (outSeq == NULL) {
12397 if (size != newSize) {
12398 /*
12399 * We need to merge and clear here, since
12400 * the sequence will contained NULLed entries.
12401 */
12402 outSeq = mergeAndClear(NULL, seq, 1);
12403 } else {
12404 outSeq = seq;
12405 seq = NULL;
12406 }
12407 } else
12408 outSeq = mergeAndClear(outSeq, seq,
12409 (size != newSize) ? 1: 0);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012410 /*
12411 * Break if only a true/false result was requested.
12412 */
12413 if (toBool)
12414 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012415 }
12416 } else if (seq->nodeNr > 0) {
12417 /*
12418 * Add to result set.
12419 */
12420 if (outSeq == NULL) {
12421 outSeq = seq;
12422 seq = NULL;
12423 } else {
12424 outSeq = mergeAndClear(outSeq, seq, 0);
12425 }
12426 }
12427 }
12428
12429error:
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012430 if ((obj->boolval) && (obj->user != NULL)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012431 /*
12432 * QUESTION TODO: What does this do and why?
12433 * TODO: Do we have to do this also for the "error"
12434 * cleanup further down?
12435 */
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012436 ctxt->value->boolval = 1;
12437 ctxt->value->user = obj->user;
12438 obj->user = NULL;
12439 obj->boolval = 0;
12440 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012441 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012442
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012443 /*
12444 * Ensure we return at least an emtpy set.
12445 */
12446 if (outSeq == NULL) {
12447 if ((seq != NULL) && (seq->nodeNr == 0))
12448 outSeq = seq;
12449 else
12450 outSeq = xmlXPathNodeSetCreate(NULL);
12451 }
12452 if ((seq != NULL) && (seq != outSeq)) {
12453 xmlXPathFreeNodeSet(seq);
12454 }
12455 /*
12456 * Hand over the result. Better to push the set also in
12457 * case of errors.
12458 */
12459 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12460 /*
12461 * Reset the context node.
12462 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012463 xpctxt->node = oldContextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012464
12465#ifdef DEBUG_STEP
12466 xmlGenericError(xmlGenericErrorContext,
12467 "\nExamined %d nodes, found %d nodes at that step\n",
12468 total, nbMatches);
12469#endif
12470
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012471 return(total);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012472}
12473
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012474static int
12475xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12476 xmlXPathStepOpPtr op, xmlNodePtr * first);
12477
Daniel Veillardf06307e2001-07-03 10:35:50 +000012478/**
12479 * xmlXPathCompOpEvalFirst:
12480 * @ctxt: the XPath parser context with the compiled expression
12481 * @op: an XPath compiled operation
12482 * @first: the first elem found so far
12483 *
12484 * Evaluate the Precompiled XPath operation searching only the first
12485 * element in document order
12486 *
12487 * Returns the number of examined objects.
12488 */
12489static int
12490xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12491 xmlXPathStepOpPtr op, xmlNodePtr * first)
12492{
12493 int total = 0, cur;
12494 xmlXPathCompExprPtr comp;
12495 xmlXPathObjectPtr arg1, arg2;
12496
Daniel Veillard556c6682001-10-06 09:59:51 +000012497 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012498 comp = ctxt->comp;
12499 switch (op->op) {
12500 case XPATH_OP_END:
12501 return (0);
12502 case XPATH_OP_UNION:
12503 total =
12504 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12505 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012506 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012507 if ((ctxt->value != NULL)
12508 && (ctxt->value->type == XPATH_NODESET)
12509 && (ctxt->value->nodesetval != NULL)
12510 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12511 /*
12512 * limit tree traversing to first node in the result
12513 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012514 /*
12515 * OPTIMIZE TODO: This implicitely sorts
12516 * the result, even if not needed. E.g. if the argument
12517 * of the count() function, no sorting is needed.
12518 * OPTIMIZE TODO: How do we know if the node-list wasn't
12519 * aready sorted?
12520 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012521 if (ctxt->value->nodesetval->nodeNr > 1)
12522 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012523 *first = ctxt->value->nodesetval->nodeTab[0];
12524 }
12525 cur =
12526 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12527 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012528 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012529 CHECK_TYPE0(XPATH_NODESET);
12530 arg2 = valuePop(ctxt);
12531
12532 CHECK_TYPE0(XPATH_NODESET);
12533 arg1 = valuePop(ctxt);
12534
12535 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12536 arg2->nodesetval);
12537 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012538 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012539 /* optimizer */
12540 if (total > cur)
12541 xmlXPathCompSwap(op);
12542 return (total + cur);
12543 case XPATH_OP_ROOT:
12544 xmlXPathRoot(ctxt);
12545 return (0);
12546 case XPATH_OP_NODE:
12547 if (op->ch1 != -1)
12548 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012549 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012550 if (op->ch2 != -1)
12551 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012552 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012553 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12554 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012555 return (total);
12556 case XPATH_OP_RESET:
12557 if (op->ch1 != -1)
12558 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012559 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012560 if (op->ch2 != -1)
12561 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012562 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012563 ctxt->context->node = NULL;
12564 return (total);
12565 case XPATH_OP_COLLECT:{
12566 if (op->ch1 == -1)
12567 return (total);
12568
12569 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012570 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012571
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012572 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012573 return (total);
12574 }
12575 case XPATH_OP_VALUE:
12576 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012577 xmlXPathCacheObjectCopy(ctxt->context,
12578 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012579 return (0);
12580 case XPATH_OP_SORT:
12581 if (op->ch1 != -1)
12582 total +=
12583 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12584 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012585 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012586 if ((ctxt->value != NULL)
12587 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012588 && (ctxt->value->nodesetval != NULL)
12589 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012590 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12591 return (total);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012592#ifdef XP_OPTIMIZED_FILTER_FIRST
12593 case XPATH_OP_FILTER:
12594 total =+ xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12595 return (total);
12596#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000012597 default:
12598 return (xmlXPathCompOpEval(ctxt, op));
12599 }
12600}
12601
12602/**
12603 * xmlXPathCompOpEvalLast:
12604 * @ctxt: the XPath parser context with the compiled expression
12605 * @op: an XPath compiled operation
12606 * @last: the last elem found so far
12607 *
12608 * Evaluate the Precompiled XPath operation searching only the last
12609 * element in document order
12610 *
William M. Brack08171912003-12-29 02:52:11 +000012611 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000012612 */
12613static int
12614xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12615 xmlNodePtr * last)
12616{
12617 int total = 0, cur;
12618 xmlXPathCompExprPtr comp;
12619 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +000012620 xmlNodePtr bak;
12621 xmlDocPtr bakd;
12622 int pp;
12623 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012624
Daniel Veillard556c6682001-10-06 09:59:51 +000012625 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012626 comp = ctxt->comp;
12627 switch (op->op) {
12628 case XPATH_OP_END:
12629 return (0);
12630 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +000012631 bakd = ctxt->context->doc;
12632 bak = ctxt->context->node;
12633 pp = ctxt->context->proximityPosition;
12634 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012635 total =
12636 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012637 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012638 if ((ctxt->value != NULL)
12639 && (ctxt->value->type == XPATH_NODESET)
12640 && (ctxt->value->nodesetval != NULL)
12641 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12642 /*
12643 * limit tree traversing to first node in the result
12644 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012645 if (ctxt->value->nodesetval->nodeNr > 1)
12646 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012647 *last =
12648 ctxt->value->nodesetval->nodeTab[ctxt->value->
12649 nodesetval->nodeNr -
12650 1];
12651 }
William M. Brackce4fc562004-01-22 02:47:18 +000012652 ctxt->context->doc = bakd;
12653 ctxt->context->node = bak;
12654 ctxt->context->proximityPosition = pp;
12655 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012656 cur =
12657 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012658 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012659 if ((ctxt->value != NULL)
12660 && (ctxt->value->type == XPATH_NODESET)
12661 && (ctxt->value->nodesetval != NULL)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012662 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012663 }
12664 CHECK_TYPE0(XPATH_NODESET);
12665 arg2 = valuePop(ctxt);
12666
12667 CHECK_TYPE0(XPATH_NODESET);
12668 arg1 = valuePop(ctxt);
12669
12670 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12671 arg2->nodesetval);
12672 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012673 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012674 /* optimizer */
12675 if (total > cur)
12676 xmlXPathCompSwap(op);
12677 return (total + cur);
12678 case XPATH_OP_ROOT:
12679 xmlXPathRoot(ctxt);
12680 return (0);
12681 case XPATH_OP_NODE:
12682 if (op->ch1 != -1)
12683 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012684 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012685 if (op->ch2 != -1)
12686 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012687 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012688 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12689 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012690 return (total);
12691 case XPATH_OP_RESET:
12692 if (op->ch1 != -1)
12693 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012694 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012695 if (op->ch2 != -1)
12696 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012697 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012698 ctxt->context->node = NULL;
12699 return (total);
12700 case XPATH_OP_COLLECT:{
12701 if (op->ch1 == -1)
12702 return (0);
12703
12704 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012705 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012706
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012707 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012708 return (total);
12709 }
12710 case XPATH_OP_VALUE:
12711 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012712 xmlXPathCacheObjectCopy(ctxt->context,
12713 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012714 return (0);
12715 case XPATH_OP_SORT:
12716 if (op->ch1 != -1)
12717 total +=
12718 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12719 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012720 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012721 if ((ctxt->value != NULL)
12722 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012723 && (ctxt->value->nodesetval != NULL)
12724 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012725 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12726 return (total);
12727 default:
12728 return (xmlXPathCompOpEval(ctxt, op));
12729 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012730}
12731
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012732#ifdef XP_OPTIMIZED_FILTER_FIRST
12733static int
12734xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12735 xmlXPathStepOpPtr op, xmlNodePtr * first)
12736{
12737 int total = 0;
12738 xmlXPathCompExprPtr comp;
12739 xmlXPathObjectPtr res;
12740 xmlXPathObjectPtr obj;
12741 xmlNodeSetPtr oldset;
12742 xmlNodePtr oldnode;
12743 xmlDocPtr oldDoc;
12744 int i;
12745
12746 CHECK_ERROR0;
12747 comp = ctxt->comp;
12748 /*
12749 * Optimization for ()[last()] selection i.e. the last elem
12750 */
12751 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12752 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12753 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12754 int f = comp->steps[op->ch2].ch1;
12755
12756 if ((f != -1) &&
12757 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12758 (comp->steps[f].value5 == NULL) &&
12759 (comp->steps[f].value == 0) &&
12760 (comp->steps[f].value4 != NULL) &&
12761 (xmlStrEqual
12762 (comp->steps[f].value4, BAD_CAST "last"))) {
12763 xmlNodePtr last = NULL;
12764
12765 total +=
12766 xmlXPathCompOpEvalLast(ctxt,
12767 &comp->steps[op->ch1],
12768 &last);
12769 CHECK_ERROR0;
12770 /*
12771 * The nodeset should be in document order,
12772 * Keep only the last value
12773 */
12774 if ((ctxt->value != NULL) &&
12775 (ctxt->value->type == XPATH_NODESET) &&
12776 (ctxt->value->nodesetval != NULL) &&
12777 (ctxt->value->nodesetval->nodeTab != NULL) &&
12778 (ctxt->value->nodesetval->nodeNr > 1)) {
12779 ctxt->value->nodesetval->nodeTab[0] =
12780 ctxt->value->nodesetval->nodeTab[ctxt->
12781 value->
12782 nodesetval->
12783 nodeNr -
12784 1];
12785 ctxt->value->nodesetval->nodeNr = 1;
12786 *first = *(ctxt->value->nodesetval->nodeTab);
12787 }
12788 return (total);
12789 }
12790 }
12791
12792 if (op->ch1 != -1)
12793 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12794 CHECK_ERROR0;
12795 if (op->ch2 == -1)
12796 return (total);
12797 if (ctxt->value == NULL)
12798 return (total);
12799
12800#ifdef LIBXML_XPTR_ENABLED
12801 oldnode = ctxt->context->node;
12802 /*
12803 * Hum are we filtering the result of an XPointer expression
12804 */
12805 if (ctxt->value->type == XPATH_LOCATIONSET) {
12806 xmlXPathObjectPtr tmp = NULL;
12807 xmlLocationSetPtr newlocset = NULL;
12808 xmlLocationSetPtr oldlocset;
12809
12810 /*
12811 * Extract the old locset, and then evaluate the result of the
12812 * expression for all the element in the locset. use it to grow
12813 * up a new locset.
12814 */
12815 CHECK_TYPE0(XPATH_LOCATIONSET);
12816 obj = valuePop(ctxt);
12817 oldlocset = obj->user;
12818 ctxt->context->node = NULL;
12819
12820 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12821 ctxt->context->contextSize = 0;
12822 ctxt->context->proximityPosition = 0;
12823 if (op->ch2 != -1)
12824 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12825 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012826 if (res != NULL) {
12827 xmlXPathReleaseObject(ctxt->context, res);
12828 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012829 valuePush(ctxt, obj);
12830 CHECK_ERROR0;
12831 return (total);
12832 }
12833 newlocset = xmlXPtrLocationSetCreate(NULL);
12834
12835 for (i = 0; i < oldlocset->locNr; i++) {
12836 /*
12837 * Run the evaluation with a node list made of a
12838 * single item in the nodelocset.
12839 */
12840 ctxt->context->node = oldlocset->locTab[i]->user;
12841 ctxt->context->contextSize = oldlocset->locNr;
12842 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012843 if (tmp == NULL) {
12844 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12845 ctxt->context->node);
12846 } else {
12847 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12848 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012849 }
12850 valuePush(ctxt, tmp);
12851 if (op->ch2 != -1)
12852 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12853 if (ctxt->error != XPATH_EXPRESSION_OK) {
12854 xmlXPathFreeObject(obj);
12855 return(0);
12856 }
12857 /*
12858 * The result of the evaluation need to be tested to
12859 * decided whether the filter succeeded or not
12860 */
12861 res = valuePop(ctxt);
12862 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12863 xmlXPtrLocationSetAdd(newlocset,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012864 xmlXPathCacheObjectCopy(ctxt->context,
12865 oldlocset->locTab[i]));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012866 }
12867 /*
12868 * Cleanup
12869 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012870 if (res != NULL) {
12871 xmlXPathReleaseObject(ctxt->context, res);
12872 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012873 if (ctxt->value == tmp) {
12874 valuePop(ctxt);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012875 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012876 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012877 * REVISIT TODO: Don't create a temporary nodeset
12878 * for everly iteration.
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012879 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012880 /* OLD: xmlXPathFreeObject(res); */
12881 } else
12882 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012883 ctxt->context->node = NULL;
12884 /*
12885 * Only put the first node in the result, then leave.
12886 */
12887 if (newlocset->locNr > 0) {
12888 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
12889 break;
12890 }
12891 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012892 if (tmp != NULL) {
12893 xmlXPathReleaseObject(ctxt->context, tmp);
12894 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012895 /*
12896 * The result is used as the new evaluation locset.
12897 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012898 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012899 ctxt->context->node = NULL;
12900 ctxt->context->contextSize = -1;
12901 ctxt->context->proximityPosition = -1;
12902 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12903 ctxt->context->node = oldnode;
12904 return (total);
12905 }
12906#endif /* LIBXML_XPTR_ENABLED */
12907
12908 /*
12909 * Extract the old set, and then evaluate the result of the
12910 * expression for all the element in the set. use it to grow
12911 * up a new set.
12912 */
12913 CHECK_TYPE0(XPATH_NODESET);
12914 obj = valuePop(ctxt);
12915 oldset = obj->nodesetval;
12916
12917 oldnode = ctxt->context->node;
12918 oldDoc = ctxt->context->doc;
12919 ctxt->context->node = NULL;
12920
12921 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
12922 ctxt->context->contextSize = 0;
12923 ctxt->context->proximityPosition = 0;
12924 /* QUESTION TODO: Why was this code commented out?
12925 if (op->ch2 != -1)
12926 total +=
12927 xmlXPathCompOpEval(ctxt,
12928 &comp->steps[op->ch2]);
12929 CHECK_ERROR0;
12930 res = valuePop(ctxt);
12931 if (res != NULL)
12932 xmlXPathFreeObject(res);
12933 */
12934 valuePush(ctxt, obj);
12935 ctxt->context->node = oldnode;
12936 CHECK_ERROR0;
12937 } else {
12938 xmlNodeSetPtr newset;
12939 xmlXPathObjectPtr tmp = NULL;
12940 /*
12941 * Initialize the new set.
12942 * Also set the xpath document in case things like
12943 * key() evaluation are attempted on the predicate
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012944 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012945 newset = xmlXPathNodeSetCreate(NULL);
12946
12947 for (i = 0; i < oldset->nodeNr; i++) {
12948 /*
12949 * Run the evaluation with a node list made of
12950 * a single item in the nodeset.
12951 */
12952 ctxt->context->node = oldset->nodeTab[i];
12953 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
12954 (oldset->nodeTab[i]->doc != NULL))
12955 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012956 if (tmp == NULL) {
12957 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12958 ctxt->context->node);
12959 } else {
12960 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12961 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012962 }
12963 valuePush(ctxt, tmp);
12964 ctxt->context->contextSize = oldset->nodeNr;
12965 ctxt->context->proximityPosition = i + 1;
12966 if (op->ch2 != -1)
12967 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12968 if (ctxt->error != XPATH_EXPRESSION_OK) {
12969 xmlXPathFreeNodeSet(newset);
12970 xmlXPathFreeObject(obj);
12971 return(0);
12972 }
12973 /*
12974 * The result of the evaluation needs to be tested to
12975 * decide whether the filter succeeded or not
12976 */
12977 res = valuePop(ctxt);
12978 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12979 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
12980 }
12981 /*
12982 * Cleanup
12983 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012984 if (res != NULL) {
12985 xmlXPathReleaseObject(ctxt->context, res);
12986 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012987 if (ctxt->value == tmp) {
12988 valuePop(ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012989 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012990 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012991 * in order to avoid massive recreation inside this
12992 * loop.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012993 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012994 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012995 } else
12996 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012997 ctxt->context->node = NULL;
12998 /*
12999 * Only put the first node in the result, then leave.
13000 */
13001 if (newset->nodeNr > 0) {
13002 *first = *(newset->nodeTab);
13003 break;
13004 }
13005 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013006 if (tmp != NULL) {
13007 xmlXPathReleaseObject(ctxt->context, tmp);
13008 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013009 /*
13010 * The result is used as the new evaluation set.
13011 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013012 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013013 ctxt->context->node = NULL;
13014 ctxt->context->contextSize = -1;
13015 ctxt->context->proximityPosition = -1;
13016 /* may want to move this past the '}' later */
13017 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013018 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013019 }
13020 ctxt->context->node = oldnode;
13021 return(total);
13022}
13023#endif /* XP_OPTIMIZED_FILTER_FIRST */
13024
Owen Taylor3473f882001-02-23 17:55:21 +000013025/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013026 * xmlXPathCompOpEval:
13027 * @ctxt: the XPath parser context with the compiled expression
13028 * @op: an XPath compiled operation
13029 *
13030 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000013031 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013032 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013033static int
13034xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13035{
13036 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013037 int equal, ret;
13038 xmlXPathCompExprPtr comp;
13039 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013040 xmlNodePtr bak;
13041 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000013042 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000013043 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013044
Daniel Veillard556c6682001-10-06 09:59:51 +000013045 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013046 comp = ctxt->comp;
13047 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013048 case XPATH_OP_END:
13049 return (0);
13050 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013051 bakd = ctxt->context->doc;
13052 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013053 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013054 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013055 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013056 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013057 xmlXPathBooleanFunction(ctxt, 1);
13058 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13059 return (total);
13060 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013061 ctxt->context->doc = bakd;
13062 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013063 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013064 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013065 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013066 if (ctxt->error) {
13067 xmlXPathFreeObject(arg2);
13068 return(0);
13069 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013070 xmlXPathBooleanFunction(ctxt, 1);
13071 arg1 = valuePop(ctxt);
13072 arg1->boolval &= arg2->boolval;
13073 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013074 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013075 return (total);
13076 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013077 bakd = ctxt->context->doc;
13078 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013079 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013080 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013081 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013082 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013083 xmlXPathBooleanFunction(ctxt, 1);
13084 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13085 return (total);
13086 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013087 ctxt->context->doc = bakd;
13088 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013089 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013090 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013091 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013092 if (ctxt->error) {
13093 xmlXPathFreeObject(arg2);
13094 return(0);
13095 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013096 xmlXPathBooleanFunction(ctxt, 1);
13097 arg1 = valuePop(ctxt);
13098 arg1->boolval |= arg2->boolval;
13099 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013100 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013101 return (total);
13102 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013103 bakd = ctxt->context->doc;
13104 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013105 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013106 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013107 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013108 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013109 ctxt->context->doc = bakd;
13110 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013111 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013112 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013113 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013114 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000013115 if (op->value)
13116 equal = xmlXPathEqualValues(ctxt);
13117 else
13118 equal = xmlXPathNotEqualValues(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013119 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013120 return (total);
13121 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013122 bakd = ctxt->context->doc;
13123 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013124 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013125 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013126 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013127 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013128 ctxt->context->doc = bakd;
13129 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013130 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013131 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013132 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013133 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013134 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013135 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013136 return (total);
13137 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013138 bakd = ctxt->context->doc;
13139 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013140 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013141 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013142 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013143 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013144 if (op->ch2 != -1) {
13145 ctxt->context->doc = bakd;
13146 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013147 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013148 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013149 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013150 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013151 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013152 if (op->value == 0)
13153 xmlXPathSubValues(ctxt);
13154 else if (op->value == 1)
13155 xmlXPathAddValues(ctxt);
13156 else if (op->value == 2)
13157 xmlXPathValueFlipSign(ctxt);
13158 else if (op->value == 3) {
13159 CAST_TO_NUMBER;
13160 CHECK_TYPE0(XPATH_NUMBER);
13161 }
13162 return (total);
13163 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013164 bakd = ctxt->context->doc;
13165 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013166 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013167 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013168 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013169 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013170 ctxt->context->doc = bakd;
13171 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013172 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013173 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013174 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013175 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013176 if (op->value == 0)
13177 xmlXPathMultValues(ctxt);
13178 else if (op->value == 1)
13179 xmlXPathDivValues(ctxt);
13180 else if (op->value == 2)
13181 xmlXPathModValues(ctxt);
13182 return (total);
13183 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013184 bakd = ctxt->context->doc;
13185 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013186 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013187 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013188 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013189 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013190 ctxt->context->doc = bakd;
13191 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013192 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013193 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013194 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013195 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013196 CHECK_TYPE0(XPATH_NODESET);
13197 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013198
Daniel Veillardf06307e2001-07-03 10:35:50 +000013199 CHECK_TYPE0(XPATH_NODESET);
13200 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013201
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013202 if ((arg1->nodesetval == NULL) ||
13203 ((arg2->nodesetval != NULL) &&
13204 (arg2->nodesetval->nodeNr != 0)))
13205 {
13206 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13207 arg2->nodesetval);
13208 }
13209
Daniel Veillardf06307e2001-07-03 10:35:50 +000013210 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013211 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013212 return (total);
13213 case XPATH_OP_ROOT:
13214 xmlXPathRoot(ctxt);
13215 return (total);
13216 case XPATH_OP_NODE:
13217 if (op->ch1 != -1)
13218 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013219 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013220 if (op->ch2 != -1)
13221 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013222 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013223 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13224 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013225 return (total);
13226 case XPATH_OP_RESET:
13227 if (op->ch1 != -1)
13228 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013229 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013230 if (op->ch2 != -1)
13231 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013232 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013233 ctxt->context->node = NULL;
13234 return (total);
13235 case XPATH_OP_COLLECT:{
13236 if (op->ch1 == -1)
13237 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000013238
Daniel Veillardf06307e2001-07-03 10:35:50 +000013239 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013240 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013241
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013242 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013243 return (total);
13244 }
13245 case XPATH_OP_VALUE:
13246 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013247 xmlXPathCacheObjectCopy(ctxt->context,
13248 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013249 return (total);
13250 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000013251 xmlXPathObjectPtr val;
13252
Daniel Veillardf06307e2001-07-03 10:35:50 +000013253 if (op->ch1 != -1)
13254 total +=
13255 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013256 if (op->value5 == NULL) {
13257 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13258 if (val == NULL) {
13259 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13260 return(0);
13261 }
13262 valuePush(ctxt, val);
13263 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013264 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013265
Daniel Veillardf06307e2001-07-03 10:35:50 +000013266 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13267 if (URI == NULL) {
13268 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013269 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000013270 op->value4, op->value5);
13271 return (total);
13272 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013273 val = xmlXPathVariableLookupNS(ctxt->context,
13274 op->value4, URI);
13275 if (val == NULL) {
13276 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13277 return(0);
13278 }
13279 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013280 }
13281 return (total);
13282 }
13283 case XPATH_OP_FUNCTION:{
13284 xmlXPathFunction func;
13285 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000013286 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013287
13288 if (op->ch1 != -1)
13289 total +=
13290 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013291 if (ctxt->valueNr < op->value) {
13292 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013293 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013294 ctxt->error = XPATH_INVALID_OPERAND;
13295 return (total);
13296 }
13297 for (i = 0; i < op->value; i++)
13298 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13299 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013300 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013301 ctxt->error = XPATH_INVALID_OPERAND;
13302 return (total);
13303 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013304 if (op->cache != NULL)
William M. Brackad0e67c2004-12-01 14:35:10 +000013305 XML_CAST_FPTR(func) = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013306 else {
13307 const xmlChar *URI = NULL;
13308
13309 if (op->value5 == NULL)
13310 func =
13311 xmlXPathFunctionLookup(ctxt->context,
13312 op->value4);
13313 else {
13314 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13315 if (URI == NULL) {
13316 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013317 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000013318 op->value4, op->value5);
13319 return (total);
13320 }
13321 func = xmlXPathFunctionLookupNS(ctxt->context,
13322 op->value4, URI);
13323 }
13324 if (func == NULL) {
13325 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013326 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000013327 op->value4);
13328 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013329 }
William M. Brackad0e67c2004-12-01 14:35:10 +000013330 op->cache = XML_CAST_FPTR(func);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013331 op->cacheURI = (void *) URI;
13332 }
13333 oldFunc = ctxt->context->function;
13334 oldFuncURI = ctxt->context->functionURI;
13335 ctxt->context->function = op->value4;
13336 ctxt->context->functionURI = op->cacheURI;
13337 func(ctxt, op->value);
13338 ctxt->context->function = oldFunc;
13339 ctxt->context->functionURI = oldFuncURI;
13340 return (total);
13341 }
13342 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000013343 bakd = ctxt->context->doc;
13344 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000013345 pp = ctxt->context->proximityPosition;
13346 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013347 if (op->ch1 != -1)
13348 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
William M. Brack645a9242004-11-09 12:20:42 +000013349 ctxt->context->contextSize = cs;
13350 ctxt->context->proximityPosition = pp;
Daniel Veillard088bf112002-05-14 11:03:59 +000013351 ctxt->context->node = bak;
William M. Brack645a9242004-11-09 12:20:42 +000013352 ctxt->context->doc = bakd;
Daniel Veillard556c6682001-10-06 09:59:51 +000013353 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000013354 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013355 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000013356 ctxt->context->doc = bakd;
13357 ctxt->context->node = bak;
13358 CHECK_ERROR0;
13359 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013360 return (total);
13361 case XPATH_OP_PREDICATE:
13362 case XPATH_OP_FILTER:{
13363 xmlXPathObjectPtr res;
13364 xmlXPathObjectPtr obj, tmp;
13365 xmlNodeSetPtr newset = NULL;
13366 xmlNodeSetPtr oldset;
13367 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000013368 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013369 int i;
13370
13371 /*
13372 * Optimization for ()[1] selection i.e. the first elem
13373 */
13374 if ((op->ch1 != -1) && (op->ch2 != -1) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013375#ifdef XP_OPTIMIZED_FILTER_FIRST
13376 /*
13377 * FILTER TODO: Can we assume that the inner processing
13378 * will result in an ordered list if we have an
13379 * XPATH_OP_FILTER?
13380 * What about an additional field or flag on
13381 * xmlXPathObject like @sorted ? This way we wouln'd need
13382 * to assume anything, so it would be more robust and
13383 * easier to optimize.
13384 */
13385 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13386 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13387#else
13388 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13389#endif
13390 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013391 xmlXPathObjectPtr val;
13392
13393 val = comp->steps[op->ch2].value4;
13394 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13395 (val->floatval == 1.0)) {
13396 xmlNodePtr first = NULL;
13397
13398 total +=
13399 xmlXPathCompOpEvalFirst(ctxt,
13400 &comp->steps[op->ch1],
13401 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000013402 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013403 /*
13404 * The nodeset should be in document order,
13405 * Keep only the first value
13406 */
13407 if ((ctxt->value != NULL) &&
13408 (ctxt->value->type == XPATH_NODESET) &&
13409 (ctxt->value->nodesetval != NULL) &&
13410 (ctxt->value->nodesetval->nodeNr > 1))
13411 ctxt->value->nodesetval->nodeNr = 1;
13412 return (total);
13413 }
13414 }
13415 /*
13416 * Optimization for ()[last()] selection i.e. the last elem
13417 */
13418 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13419 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13420 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13421 int f = comp->steps[op->ch2].ch1;
13422
13423 if ((f != -1) &&
13424 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13425 (comp->steps[f].value5 == NULL) &&
13426 (comp->steps[f].value == 0) &&
13427 (comp->steps[f].value4 != NULL) &&
13428 (xmlStrEqual
13429 (comp->steps[f].value4, BAD_CAST "last"))) {
13430 xmlNodePtr last = NULL;
13431
13432 total +=
13433 xmlXPathCompOpEvalLast(ctxt,
13434 &comp->steps[op->ch1],
13435 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000013436 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013437 /*
13438 * The nodeset should be in document order,
13439 * Keep only the last value
13440 */
13441 if ((ctxt->value != NULL) &&
13442 (ctxt->value->type == XPATH_NODESET) &&
13443 (ctxt->value->nodesetval != NULL) &&
13444 (ctxt->value->nodesetval->nodeTab != NULL) &&
13445 (ctxt->value->nodesetval->nodeNr > 1)) {
13446 ctxt->value->nodesetval->nodeTab[0] =
13447 ctxt->value->nodesetval->nodeTab[ctxt->
13448 value->
13449 nodesetval->
13450 nodeNr -
13451 1];
13452 ctxt->value->nodesetval->nodeNr = 1;
13453 }
13454 return (total);
13455 }
13456 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013457 /*
13458 * Process inner predicates first.
13459 * Example "index[parent::book][1]":
13460 * ...
13461 * PREDICATE <-- we are here "[1]"
13462 * PREDICATE <-- process "[parent::book]" first
13463 * SORT
13464 * COLLECT 'parent' 'name' 'node' book
13465 * NODE
13466 * ELEM Object is a number : 1
13467 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013468 if (op->ch1 != -1)
13469 total +=
13470 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013471 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013472 if (op->ch2 == -1)
13473 return (total);
13474 if (ctxt->value == NULL)
13475 return (total);
13476
13477 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013478
13479#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013480 /*
13481 * Hum are we filtering the result of an XPointer expression
13482 */
13483 if (ctxt->value->type == XPATH_LOCATIONSET) {
13484 xmlLocationSetPtr newlocset = NULL;
13485 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013486
Daniel Veillardf06307e2001-07-03 10:35:50 +000013487 /*
13488 * Extract the old locset, and then evaluate the result of the
13489 * expression for all the element in the locset. use it to grow
13490 * up a new locset.
13491 */
13492 CHECK_TYPE0(XPATH_LOCATIONSET);
13493 obj = valuePop(ctxt);
13494 oldlocset = obj->user;
13495 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013496
Daniel Veillardf06307e2001-07-03 10:35:50 +000013497 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13498 ctxt->context->contextSize = 0;
13499 ctxt->context->proximityPosition = 0;
13500 if (op->ch2 != -1)
13501 total +=
13502 xmlXPathCompOpEval(ctxt,
13503 &comp->steps[op->ch2]);
13504 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013505 if (res != NULL) {
13506 xmlXPathReleaseObject(ctxt->context, res);
13507 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013508 valuePush(ctxt, obj);
13509 CHECK_ERROR0;
13510 return (total);
13511 }
13512 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013513
Daniel Veillardf06307e2001-07-03 10:35:50 +000013514 for (i = 0; i < oldlocset->locNr; i++) {
13515 /*
13516 * Run the evaluation with a node list made of a
13517 * single item in the nodelocset.
13518 */
13519 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013520 ctxt->context->contextSize = oldlocset->locNr;
13521 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013522 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13523 ctxt->context->node);
William M. Brackf7eb7942003-12-31 07:59:17 +000013524 valuePush(ctxt, tmp);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013525
Daniel Veillardf06307e2001-07-03 10:35:50 +000013526 if (op->ch2 != -1)
13527 total +=
13528 xmlXPathCompOpEval(ctxt,
13529 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013530 if (ctxt->error != XPATH_EXPRESSION_OK) {
13531 xmlXPathFreeObject(obj);
13532 return(0);
13533 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013534
Daniel Veillardf06307e2001-07-03 10:35:50 +000013535 /*
13536 * The result of the evaluation need to be tested to
13537 * decided whether the filter succeeded or not
13538 */
13539 res = valuePop(ctxt);
13540 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13541 xmlXPtrLocationSetAdd(newlocset,
13542 xmlXPathObjectCopy
13543 (oldlocset->locTab[i]));
13544 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013545
Daniel Veillardf06307e2001-07-03 10:35:50 +000013546 /*
13547 * Cleanup
13548 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013549 if (res != NULL) {
13550 xmlXPathReleaseObject(ctxt->context, res);
13551 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013552 if (ctxt->value == tmp) {
13553 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013554 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013555 }
13556
13557 ctxt->context->node = NULL;
13558 }
13559
13560 /*
13561 * The result is used as the new evaluation locset.
13562 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013563 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013564 ctxt->context->node = NULL;
13565 ctxt->context->contextSize = -1;
13566 ctxt->context->proximityPosition = -1;
13567 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13568 ctxt->context->node = oldnode;
13569 return (total);
13570 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013571#endif /* LIBXML_XPTR_ENABLED */
13572
Daniel Veillardf06307e2001-07-03 10:35:50 +000013573 /*
13574 * Extract the old set, and then evaluate the result of the
13575 * expression for all the element in the set. use it to grow
13576 * up a new set.
13577 */
13578 CHECK_TYPE0(XPATH_NODESET);
13579 obj = valuePop(ctxt);
13580 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000013581
Daniel Veillardf06307e2001-07-03 10:35:50 +000013582 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000013583 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013584 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013585
Daniel Veillardf06307e2001-07-03 10:35:50 +000013586 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13587 ctxt->context->contextSize = 0;
13588 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000013589/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000013590 if (op->ch2 != -1)
13591 total +=
13592 xmlXPathCompOpEval(ctxt,
13593 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013594 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013595 res = valuePop(ctxt);
13596 if (res != NULL)
13597 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000013598*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000013599 valuePush(ctxt, obj);
13600 ctxt->context->node = oldnode;
13601 CHECK_ERROR0;
13602 } else {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013603 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013604 /*
13605 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000013606 * Also set the xpath document in case things like
13607 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000013608 */
13609 newset = xmlXPathNodeSetCreate(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013610 /*
13611 * SPEC XPath 1.0:
13612 * "For each node in the node-set to be filtered, the
13613 * PredicateExpr is evaluated with that node as the
13614 * context node, with the number of nodes in the
13615 * node-set as the context size, and with the proximity
13616 * position of the node in the node-set with respect to
13617 * the axis as the context position;"
13618 * @oldset is the node-set" to be filtered.
13619 *
13620 * SPEC XPath 1.0:
13621 * "only predicates change the context position and
13622 * context size (see [2.4 Predicates])."
13623 * Example:
13624 * node-set context pos
13625 * nA 1
13626 * nB 2
13627 * nC 3
13628 * After applying predicate [position() > 1] :
13629 * node-set context pos
13630 * nB 1
13631 * nC 2
13632 *
13633 * removed the first node in the node-set, then
13634 * the context position of the
13635 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013636 for (i = 0; i < oldset->nodeNr; i++) {
13637 /*
13638 * Run the evaluation with a node list made of
13639 * a single item in the nodeset.
13640 */
13641 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000013642 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13643 (oldset->nodeTab[i]->doc != NULL))
13644 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013645 if (tmp == NULL) {
13646 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13647 ctxt->context->node);
13648 } else {
13649 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13650 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013651 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013652 valuePush(ctxt, tmp);
13653 ctxt->context->contextSize = oldset->nodeNr;
13654 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013655 /*
13656 * Evaluate the predicate against the context node.
13657 * Can/should we optimize position() predicates
13658 * here (e.g. "[1]")?
13659 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013660 if (op->ch2 != -1)
13661 total +=
13662 xmlXPathCompOpEval(ctxt,
13663 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013664 if (ctxt->error != XPATH_EXPRESSION_OK) {
13665 xmlXPathFreeNodeSet(newset);
13666 xmlXPathFreeObject(obj);
13667 return(0);
13668 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013669
Daniel Veillardf06307e2001-07-03 10:35:50 +000013670 /*
William M. Brack08171912003-12-29 02:52:11 +000013671 * The result of the evaluation needs to be tested to
13672 * decide whether the filter succeeded or not
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013673 */
13674 /*
13675 * OPTIMIZE TODO: Can we use
13676 * xmlXPathNodeSetAdd*Unique()* instead?
13677 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013678 res = valuePop(ctxt);
13679 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13680 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13681 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013682
Daniel Veillardf06307e2001-07-03 10:35:50 +000013683 /*
13684 * Cleanup
13685 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013686 if (res != NULL) {
13687 xmlXPathReleaseObject(ctxt->context, res);
13688 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013689 if (ctxt->value == tmp) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013690 valuePop(ctxt);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000013691 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013692 /*
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013693 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013694 * in order to avoid massive recreation inside this
13695 * loop.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013696 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013697 } else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013698 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013699 ctxt->context->node = NULL;
13700 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013701 if (tmp != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013702 xmlXPathReleaseObject(ctxt->context, tmp);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013703 /*
13704 * The result is used as the new evaluation set.
13705 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013706 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013707 ctxt->context->node = NULL;
13708 ctxt->context->contextSize = -1;
13709 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000013710 /* may want to move this past the '}' later */
13711 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013712 valuePush(ctxt,
13713 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013714 }
13715 ctxt->context->node = oldnode;
13716 return (total);
13717 }
13718 case XPATH_OP_SORT:
13719 if (op->ch1 != -1)
13720 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013721 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013722 if ((ctxt->value != NULL) &&
13723 (ctxt->value->type == XPATH_NODESET) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013724 (ctxt->value->nodesetval != NULL) &&
13725 (ctxt->value->nodesetval->nodeNr > 1))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013726 {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013727 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013728 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013729 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013730#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013731 case XPATH_OP_RANGETO:{
13732 xmlXPathObjectPtr range;
13733 xmlXPathObjectPtr res, obj;
13734 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000013735 xmlLocationSetPtr newlocset = NULL;
13736 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013737 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000013738 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013739
Daniel Veillardf06307e2001-07-03 10:35:50 +000013740 if (op->ch1 != -1)
13741 total +=
13742 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13743 if (op->ch2 == -1)
13744 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013745
William M. Brack08171912003-12-29 02:52:11 +000013746 if (ctxt->value->type == XPATH_LOCATIONSET) {
13747 /*
13748 * Extract the old locset, and then evaluate the result of the
13749 * expression for all the element in the locset. use it to grow
13750 * up a new locset.
13751 */
13752 CHECK_TYPE0(XPATH_LOCATIONSET);
13753 obj = valuePop(ctxt);
13754 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013755
William M. Brack08171912003-12-29 02:52:11 +000013756 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000013757 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000013758 ctxt->context->contextSize = 0;
13759 ctxt->context->proximityPosition = 0;
13760 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13761 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013762 if (res != NULL) {
13763 xmlXPathReleaseObject(ctxt->context, res);
13764 }
William M. Brack08171912003-12-29 02:52:11 +000013765 valuePush(ctxt, obj);
13766 CHECK_ERROR0;
13767 return (total);
13768 }
13769 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013770
William M. Brack08171912003-12-29 02:52:11 +000013771 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013772 /*
William M. Brack08171912003-12-29 02:52:11 +000013773 * Run the evaluation with a node list made of a
13774 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000013775 */
William M. Brackf7eb7942003-12-31 07:59:17 +000013776 ctxt->context->node = oldlocset->locTab[i]->user;
13777 ctxt->context->contextSize = oldlocset->locNr;
13778 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013779 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13780 ctxt->context->node);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013781 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013782
Daniel Veillardf06307e2001-07-03 10:35:50 +000013783 if (op->ch2 != -1)
13784 total +=
13785 xmlXPathCompOpEval(ctxt,
13786 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013787 if (ctxt->error != XPATH_EXPRESSION_OK) {
13788 xmlXPathFreeObject(obj);
13789 return(0);
13790 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013791
Daniel Veillardf06307e2001-07-03 10:35:50 +000013792 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000013793 if (res->type == XPATH_LOCATIONSET) {
13794 xmlLocationSetPtr rloc =
13795 (xmlLocationSetPtr)res->user;
13796 for (j=0; j<rloc->locNr; j++) {
13797 range = xmlXPtrNewRange(
13798 oldlocset->locTab[i]->user,
13799 oldlocset->locTab[i]->index,
13800 rloc->locTab[j]->user2,
13801 rloc->locTab[j]->index2);
13802 if (range != NULL) {
13803 xmlXPtrLocationSetAdd(newlocset, range);
13804 }
13805 }
13806 } else {
13807 range = xmlXPtrNewRangeNodeObject(
13808 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13809 if (range != NULL) {
13810 xmlXPtrLocationSetAdd(newlocset,range);
13811 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013812 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013813
Daniel Veillardf06307e2001-07-03 10:35:50 +000013814 /*
13815 * Cleanup
13816 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013817 if (res != NULL) {
13818 xmlXPathReleaseObject(ctxt->context, res);
13819 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013820 if (ctxt->value == tmp) {
13821 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013822 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013823 }
13824
13825 ctxt->context->node = NULL;
13826 }
William M. Brack72ee48d2003-12-30 08:30:19 +000013827 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000013828 CHECK_TYPE0(XPATH_NODESET);
13829 obj = valuePop(ctxt);
13830 oldset = obj->nodesetval;
13831 ctxt->context->node = NULL;
13832
13833 newlocset = xmlXPtrLocationSetCreate(NULL);
13834
13835 if (oldset != NULL) {
13836 for (i = 0; i < oldset->nodeNr; i++) {
13837 /*
13838 * Run the evaluation with a node list made of a single item
13839 * in the nodeset.
13840 */
13841 ctxt->context->node = oldset->nodeTab[i];
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013842 /*
13843 * OPTIMIZE TODO: Avoid recreation for every iteration.
13844 */
13845 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13846 ctxt->context->node);
William M. Brack08171912003-12-29 02:52:11 +000013847 valuePush(ctxt, tmp);
13848
13849 if (op->ch2 != -1)
13850 total +=
13851 xmlXPathCompOpEval(ctxt,
13852 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013853 if (ctxt->error != XPATH_EXPRESSION_OK) {
13854 xmlXPathFreeObject(obj);
13855 return(0);
13856 }
William M. Brack08171912003-12-29 02:52:11 +000013857
William M. Brack08171912003-12-29 02:52:11 +000013858 res = valuePop(ctxt);
13859 range =
13860 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13861 res);
13862 if (range != NULL) {
13863 xmlXPtrLocationSetAdd(newlocset, range);
13864 }
13865
13866 /*
13867 * Cleanup
13868 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013869 if (res != NULL) {
13870 xmlXPathReleaseObject(ctxt->context, res);
13871 }
William M. Brack08171912003-12-29 02:52:11 +000013872 if (ctxt->value == tmp) {
13873 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013874 xmlXPathReleaseObject(ctxt->context, res);
William M. Brack08171912003-12-29 02:52:11 +000013875 }
13876
13877 ctxt->context->node = NULL;
13878 }
13879 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013880 }
13881
13882 /*
13883 * The result is used as the new evaluation set.
13884 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013885 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013886 ctxt->context->node = NULL;
13887 ctxt->context->contextSize = -1;
13888 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000013889 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013890 return (total);
13891 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013892#endif /* LIBXML_XPTR_ENABLED */
13893 }
13894 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000013895 "XPath: unknown precompiled operation %d\n", op->op);
13896 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013897}
13898
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013899/**
13900 * xmlXPathCompOpEvalToBoolean:
13901 * @ctxt: the XPath parser context
13902 *
13903 * Evaluates if the expression evaluates to true.
13904 *
13905 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13906 */
13907static int
13908xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013909 xmlXPathStepOpPtr op,
13910 int isPredicate)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013911{
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013912 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013913
13914start:
13915 /* comp = ctxt->comp; */
13916 switch (op->op) {
13917 case XPATH_OP_END:
13918 return (0);
13919 case XPATH_OP_VALUE:
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013920 resObj = (xmlXPathObjectPtr) op->value4;
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000013921 if (isPredicate)
13922 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13923 return(xmlXPathCastToBoolean(resObj));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013924 case XPATH_OP_SORT:
13925 /*
13926 * We don't need sorting for boolean results. Skip this one.
13927 */
13928 if (op->ch1 != -1) {
13929 op = &ctxt->comp->steps[op->ch1];
13930 goto start;
13931 }
13932 return(0);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013933 case XPATH_OP_COLLECT:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013934 if (op->ch1 == -1)
13935 return(0);
13936
13937 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13938 if (ctxt->error != XPATH_EXPRESSION_OK)
13939 return(-1);
13940
13941 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13942 if (ctxt->error != XPATH_EXPRESSION_OK)
13943 return(-1);
13944
13945 resObj = valuePop(ctxt);
13946 if (resObj == NULL)
13947 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013948 break;
13949 default:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013950 /*
13951 * Fallback to call xmlXPathCompOpEval().
13952 */
13953 xmlXPathCompOpEval(ctxt, op);
13954 if (ctxt->error != XPATH_EXPRESSION_OK)
13955 return(-1);
13956
13957 resObj = valuePop(ctxt);
13958 if (resObj == NULL)
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000013959 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013960 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013961 }
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013962
13963 if (resObj) {
13964 int res;
13965
13966 if (resObj->type == XPATH_BOOLEAN) {
13967 res = resObj->boolval;
13968 } else if (isPredicate) {
13969 /*
13970 * For predicates a result of type "number" is handled
13971 * differently:
13972 * SPEC XPath 1.0:
13973 * "If the result is a number, the result will be converted
13974 * to true if the number is equal to the context position
13975 * and will be converted to false otherwise;"
13976 */
13977 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
13978 } else {
13979 res = xmlXPathCastToBoolean(resObj);
13980 }
13981 xmlXPathReleaseObject(ctxt->context, resObj);
13982 return(res);
13983 }
13984
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013985 return(0);
13986}
13987
Daniel Veillard56de87e2005-02-16 00:22:29 +000013988#ifdef XPATH_STREAMING
13989/**
13990 * xmlXPathRunStreamEval:
13991 * @ctxt: the XPath parser context with the compiled expression
13992 *
13993 * Evaluate the Precompiled Streamable XPath expression in the given context.
13994 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013995static int
13996xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
13997 xmlXPathObjectPtr *resultSeq, int toBool)
13998{
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013999 int max_depth, min_depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014000 int from_root;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014001 int ret, depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014002 int eval_all_nodes;
William M. Brack12d37ab2005-02-21 13:54:07 +000014003 xmlNodePtr cur = NULL, limit = NULL;
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014004 xmlStreamCtxtPtr patstream = NULL;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014005
14006 int nb_nodes = 0;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014007
14008 if ((ctxt == NULL) || (comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014009 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014010 max_depth = xmlPatternMaxDepth(comp);
14011 if (max_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014012 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014013 if (max_depth == -2)
14014 max_depth = 10000;
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014015 min_depth = xmlPatternMinDepth(comp);
14016 if (min_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014017 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014018 from_root = xmlPatternFromRoot(comp);
14019 if (from_root < 0)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014020 return(-1);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014021#if 0
14022 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14023#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000014024
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014025 if (! toBool) {
14026 if (resultSeq == NULL)
14027 return(-1);
14028 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14029 if (*resultSeq == NULL)
14030 return(-1);
14031 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014032
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014033 /*
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014034 * handle the special cases of "/" amd "." being matched
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014035 */
14036 if (min_depth == 0) {
14037 if (from_root) {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014038 /* Select "/" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014039 if (toBool)
14040 return(1);
14041 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14042 (xmlNodePtr) ctxt->doc);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014043 } else {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014044 /* Select "self::node()" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014045 if (toBool)
14046 return(1);
14047 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014048 }
14049 }
14050 if (max_depth == 0) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014051 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014052 }
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014053
Daniel Veillard56de87e2005-02-16 00:22:29 +000014054 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000014055 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014056 } else if (ctxt->node != NULL) {
14057 switch (ctxt->node->type) {
14058 case XML_ELEMENT_NODE:
14059 case XML_DOCUMENT_NODE:
14060 case XML_DOCUMENT_FRAG_NODE:
14061 case XML_HTML_DOCUMENT_NODE:
14062#ifdef LIBXML_DOCB_ENABLED
14063 case XML_DOCB_DOCUMENT_NODE:
14064#endif
14065 cur = ctxt->node;
14066 break;
14067 case XML_ATTRIBUTE_NODE:
14068 case XML_TEXT_NODE:
14069 case XML_CDATA_SECTION_NODE:
14070 case XML_ENTITY_REF_NODE:
14071 case XML_ENTITY_NODE:
14072 case XML_PI_NODE:
14073 case XML_COMMENT_NODE:
14074 case XML_NOTATION_NODE:
14075 case XML_DTD_NODE:
14076 case XML_DOCUMENT_TYPE_NODE:
14077 case XML_ELEMENT_DECL:
14078 case XML_ATTRIBUTE_DECL:
14079 case XML_ENTITY_DECL:
14080 case XML_NAMESPACE_DECL:
14081 case XML_XINCLUDE_START:
14082 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000014083 break;
14084 }
14085 limit = cur;
14086 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014087 if (cur == NULL) {
14088 return(0);
14089 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014090
14091 patstream = xmlPatternGetStreamCtxt(comp);
14092 if (patstream == NULL) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014093 /*
14094 * QUESTION TODO: Is this an error?
14095 */
14096 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014097 }
14098
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014099 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014100
Daniel Veillard56de87e2005-02-16 00:22:29 +000014101 if (from_root) {
14102 ret = xmlStreamPush(patstream, NULL, NULL);
14103 if (ret < 0) {
14104 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014105 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014106 goto return_1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014107 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014108 }
14109 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014110 depth = 0;
14111 goto scan_children;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014112next_node:
Daniel Veillardd3ff7ef2006-02-27 19:43:17 +000014113 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014114 nb_nodes++;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014115
14116 switch (cur->type) {
14117 case XML_ELEMENT_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014118 case XML_TEXT_NODE:
14119 case XML_CDATA_SECTION_NODE:
14120 case XML_COMMENT_NODE:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014121 case XML_PI_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014122 if (cur->type == XML_ELEMENT_NODE) {
14123 ret = xmlStreamPush(patstream, cur->name,
Daniel Veillard56de87e2005-02-16 00:22:29 +000014124 (cur->ns ? cur->ns->href : NULL));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014125 } else if (eval_all_nodes)
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014126 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14127 else
14128 break;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014129
14130 if (ret < 0) {
14131 /* NOP. */
14132 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014133 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014134 goto return_1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014135 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014136 }
14137 if ((cur->children == NULL) || (depth >= max_depth)) {
14138 ret = xmlStreamPop(patstream);
14139 while (cur->next != NULL) {
14140 cur = cur->next;
14141 if ((cur->type != XML_ENTITY_DECL) &&
14142 (cur->type != XML_DTD_NODE))
14143 goto next_node;
14144 }
14145 }
14146 default:
14147 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014148 }
14149
Daniel Veillard56de87e2005-02-16 00:22:29 +000014150scan_children:
14151 if ((cur->children != NULL) && (depth < max_depth)) {
14152 /*
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014153 * Do not descend on entities declarations
Daniel Veillard56de87e2005-02-16 00:22:29 +000014154 */
14155 if (cur->children->type != XML_ENTITY_DECL) {
14156 cur = cur->children;
14157 depth++;
14158 /*
14159 * Skip DTDs
14160 */
14161 if (cur->type != XML_DTD_NODE)
14162 continue;
14163 }
14164 }
14165
14166 if (cur == limit)
14167 break;
14168
14169 while (cur->next != NULL) {
14170 cur = cur->next;
14171 if ((cur->type != XML_ENTITY_DECL) &&
14172 (cur->type != XML_DTD_NODE))
14173 goto next_node;
14174 }
14175
14176 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014177 cur = cur->parent;
14178 depth--;
14179 if ((cur == NULL) || (cur == limit))
14180 goto done;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014181 if (cur->type == XML_ELEMENT_NODE) {
14182 ret = xmlStreamPop(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014183 } else if ((eval_all_nodes) &&
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014184 ((cur->type == XML_TEXT_NODE) ||
14185 (cur->type == XML_CDATA_SECTION_NODE) ||
14186 (cur->type == XML_COMMENT_NODE) ||
14187 (cur->type == XML_PI_NODE)))
14188 {
14189 ret = xmlStreamPop(patstream);
14190 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014191 if (cur->next != NULL) {
14192 cur = cur->next;
14193 break;
14194 }
14195 } while (cur != NULL);
14196
14197 } while ((cur != NULL) && (depth >= 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014198
Daniel Veillard56de87e2005-02-16 00:22:29 +000014199done:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014200
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014201#if 0
14202 printf("stream eval: checked %d nodes selected %d\n",
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014203 nb_nodes, retObj->nodesetval->nodeNr);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014204#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014205
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014206 if (patstream)
14207 xmlFreeStreamCtxt(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014208 return(0);
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014209
14210return_1:
14211 if (patstream)
14212 xmlFreeStreamCtxt(patstream);
14213 return(1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014214}
14215#endif /* XPATH_STREAMING */
14216
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014217/**
14218 * xmlXPathRunEval:
14219 * @ctxt: the XPath parser context with the compiled expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014220 * @toBool: evaluate to a boolean result
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014221 *
14222 * Evaluate the Precompiled XPath expression in the given context.
14223 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014224static int
14225xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14226{
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014227 xmlXPathCompExprPtr comp;
14228
14229 if ((ctxt == NULL) || (ctxt->comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014230 return(-1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014231
14232 if (ctxt->valueTab == NULL) {
14233 /* Allocate the value stack */
14234 ctxt->valueTab = (xmlXPathObjectPtr *)
14235 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14236 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000014237 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014238 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014239 }
14240 ctxt->valueNr = 0;
14241 ctxt->valueMax = 10;
14242 ctxt->value = NULL;
14243 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014244#ifdef XPATH_STREAMING
14245 if (ctxt->comp->stream) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014246 int res;
14247
14248 if (toBool) {
14249 /*
14250 * Evaluation to boolean result.
14251 */
14252 res = xmlXPathRunStreamEval(ctxt->context,
14253 ctxt->comp->stream, NULL, 1);
14254 if (res != -1)
14255 return(res);
14256 } else {
14257 xmlXPathObjectPtr resObj = NULL;
14258
14259 /*
14260 * Evaluation to a sequence.
14261 */
14262 res = xmlXPathRunStreamEval(ctxt->context,
14263 ctxt->comp->stream, &resObj, 0);
14264
14265 if ((res != -1) && (resObj != NULL)) {
14266 valuePush(ctxt, resObj);
14267 return(0);
14268 }
14269 if (resObj != NULL)
14270 xmlXPathReleaseObject(ctxt->context, resObj);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014271 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014272 /*
14273 * QUESTION TODO: This falls back to normal XPath evaluation
14274 * if res == -1. Is this intended?
14275 */
Daniel Veillard56de87e2005-02-16 00:22:29 +000014276 }
14277#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014278 comp = ctxt->comp;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014279 if (comp->last < 0) {
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014280 xmlGenericError(xmlGenericErrorContext,
14281 "xmlXPathRunEval: last is less than zero\n");
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014282 return(-1);
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014283 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014284 if (toBool)
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014285 return(xmlXPathCompOpEvalToBoolean(ctxt,
14286 &comp->steps[comp->last], 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014287 else
14288 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14289
14290 return(0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014291}
14292
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014293/************************************************************************
14294 * *
14295 * Public interfaces *
14296 * *
14297 ************************************************************************/
14298
14299/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014300 * xmlXPathEvalPredicate:
14301 * @ctxt: the XPath context
14302 * @res: the Predicate Expression evaluation result
14303 *
14304 * Evaluate a predicate result for the current node.
14305 * A PredicateExpr is evaluated by evaluating the Expr and converting
14306 * the result to a boolean. If the result is a number, the result will
14307 * be converted to true if the number is equal to the position of the
14308 * context node in the context node list (as returned by the position
14309 * function) and will be converted to false otherwise; if the result
14310 * is not a number, then the result will be converted as if by a call
14311 * to the boolean function.
14312 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014313 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014314 */
14315int
14316xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014317 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014318 switch (res->type) {
14319 case XPATH_BOOLEAN:
14320 return(res->boolval);
14321 case XPATH_NUMBER:
14322 return(res->floatval == ctxt->proximityPosition);
14323 case XPATH_NODESET:
14324 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000014325 if (res->nodesetval == NULL)
14326 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014327 return(res->nodesetval->nodeNr != 0);
14328 case XPATH_STRING:
14329 return((res->stringval != NULL) &&
14330 (xmlStrlen(res->stringval) != 0));
14331 default:
14332 STRANGE
14333 }
14334 return(0);
14335}
14336
14337/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014338 * xmlXPathEvaluatePredicateResult:
14339 * @ctxt: the XPath Parser context
14340 * @res: the Predicate Expression evaluation result
14341 *
14342 * Evaluate a predicate result for the current node.
14343 * A PredicateExpr is evaluated by evaluating the Expr and converting
14344 * the result to a boolean. If the result is a number, the result will
14345 * be converted to true if the number is equal to the position of the
14346 * context node in the context node list (as returned by the position
14347 * function) and will be converted to false otherwise; if the result
14348 * is not a number, then the result will be converted as if by a call
14349 * to the boolean function.
14350 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014351 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014352 */
14353int
14354xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14355 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014356 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014357 switch (res->type) {
14358 case XPATH_BOOLEAN:
14359 return(res->boolval);
14360 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000014361#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000014362 return((res->floatval == ctxt->context->proximityPosition) &&
14363 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000014364#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014365 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000014366#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014367 case XPATH_NODESET:
14368 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000014369 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000014370 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014371 return(res->nodesetval->nodeNr != 0);
14372 case XPATH_STRING:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014373 return((res->stringval != NULL) && (res->stringval[0] != 0));
William M. Brack08171912003-12-29 02:52:11 +000014374#ifdef LIBXML_XPTR_ENABLED
14375 case XPATH_LOCATIONSET:{
14376 xmlLocationSetPtr ptr = res->user;
14377 if (ptr == NULL)
14378 return(0);
14379 return (ptr->locNr != 0);
14380 }
14381#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014382 default:
14383 STRANGE
14384 }
14385 return(0);
14386}
14387
Daniel Veillard56de87e2005-02-16 00:22:29 +000014388#ifdef XPATH_STREAMING
14389/**
14390 * xmlXPathTryStreamCompile:
14391 * @ctxt: an XPath context
14392 * @str: the XPath expression
14393 *
14394 * Try to compile the XPath expression as a streamable subset.
14395 *
14396 * Returns the compiled expression or NULL if failed to compile.
14397 */
14398static xmlXPathCompExprPtr
14399xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14400 /*
14401 * Optimization: use streaming patterns when the XPath expression can
14402 * be compiled to a stream lookup
14403 */
14404 xmlPatternPtr stream;
14405 xmlXPathCompExprPtr comp;
14406 xmlDictPtr dict = NULL;
14407 const xmlChar **namespaces = NULL;
14408 xmlNsPtr ns;
14409 int i, j;
14410
14411 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14412 (!xmlStrchr(str, '@'))) {
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014413 const xmlChar *tmp;
14414
14415 /*
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014416 * We don't try to handle expressions using the verbose axis
14417 * specifiers ("::"), just the simplied form at this point.
14418 * Additionally, if there is no list of namespaces available and
14419 * there's a ":" in the expression, indicating a prefixed QName,
14420 * then we won't try to compile either. xmlPatterncompile() needs
14421 * to have a list of namespaces at compilation time in order to
14422 * compile prefixed name tests.
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014423 */
14424 tmp = xmlStrchr(str, ':');
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014425 if ((tmp != NULL) &&
14426 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14427 return(NULL);
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014428
Daniel Veillard56de87e2005-02-16 00:22:29 +000014429 if (ctxt != NULL) {
14430 dict = ctxt->dict;
14431 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000014432 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000014433 if (namespaces == NULL) {
14434 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14435 return(NULL);
14436 }
14437 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14438 ns = ctxt->namespaces[j];
14439 namespaces[i++] = ns->href;
14440 namespaces[i++] = ns->prefix;
14441 }
14442 namespaces[i++] = NULL;
14443 namespaces[i++] = NULL;
14444 }
14445 }
14446
William M. Brackea152c02005-06-09 18:12:28 +000014447 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14448 &namespaces[0]);
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014449 if (namespaces != NULL) {
14450 xmlFree((xmlChar **)namespaces);
14451 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014452 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14453 comp = xmlXPathNewCompExpr();
14454 if (comp == NULL) {
14455 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14456 return(NULL);
14457 }
14458 comp->stream = stream;
14459 comp->dict = dict;
14460 if (comp->dict)
14461 xmlDictReference(comp->dict);
14462 return(comp);
14463 }
14464 xmlFreePattern(stream);
14465 }
14466 return(NULL);
14467}
14468#endif /* XPATH_STREAMING */
14469
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014470static int
14471xmlXPathCanRewriteDosExpression(xmlChar *expr)
14472{
14473 if (expr == NULL)
14474 return(0);
14475 do {
14476 if ((*expr == '/') && (*(++expr) == '/'))
14477 return(1);
14478 } while (*expr++);
14479 return(0);
14480}
14481static void
14482xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14483{
14484 /*
14485 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14486 * internal representation.
14487 */
14488 if (op->ch1 != -1) {
14489 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14490 ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
14491 ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
14492 ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
14493 {
14494 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014495 * This is a "child::foo"
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014496 */
14497 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14498
14499 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14500 (prevop->ch1 != -1) &&
14501 ((xmlXPathAxisVal) prevop->value ==
14502 AXIS_DESCENDANT_OR_SELF) &&
14503 (prevop->ch2 == -1) &&
14504 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014505 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
14506 (comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014507 {
14508 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014509 * This is a "/descendant-or-self::node()" without predicates.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014510 * Eliminate it.
14511 */
14512 op->ch1 = prevop->ch1;
14513 op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
14514 }
14515 }
14516 if (op->ch1 != -1)
14517 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
14518 }
14519 if (op->ch2 != -1)
14520 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
14521}
14522
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014523/**
Daniel Veillard4773df22004-01-23 13:15:13 +000014524 * xmlXPathCtxtCompile:
14525 * @ctxt: an XPath context
14526 * @str: the XPath expression
14527 *
14528 * Compile an XPath expression
14529 *
14530 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14531 * the caller has to free the object.
14532 */
14533xmlXPathCompExprPtr
14534xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14535 xmlXPathParserContextPtr pctxt;
14536 xmlXPathCompExprPtr comp;
14537
Daniel Veillard56de87e2005-02-16 00:22:29 +000014538#ifdef XPATH_STREAMING
14539 comp = xmlXPathTryStreamCompile(ctxt, str);
14540 if (comp != NULL)
14541 return(comp);
14542#endif
14543
Daniel Veillard4773df22004-01-23 13:15:13 +000014544 xmlXPathInit();
14545
14546 pctxt = xmlXPathNewParserContext(str, ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014547 xmlXPathCompileExpr(pctxt, 1);
Daniel Veillard4773df22004-01-23 13:15:13 +000014548
14549 if( pctxt->error != XPATH_EXPRESSION_OK )
14550 {
14551 xmlXPathFreeParserContext(pctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000014552 return(NULL);
Daniel Veillard4773df22004-01-23 13:15:13 +000014553 }
14554
14555 if (*pctxt->cur != 0) {
14556 /*
14557 * aleksey: in some cases this line prints *second* error message
14558 * (see bug #78858) and probably this should be fixed.
14559 * However, we are not sure that all error messages are printed
14560 * out in other places. It's not critical so we leave it as-is for now
14561 */
14562 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14563 comp = NULL;
14564 } else {
14565 comp = pctxt->comp;
14566 pctxt->comp = NULL;
14567 }
14568 xmlXPathFreeParserContext(pctxt);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014569
Daniel Veillard4773df22004-01-23 13:15:13 +000014570 if (comp != NULL) {
14571 comp->expr = xmlStrdup(str);
14572#ifdef DEBUG_EVAL_COUNTS
14573 comp->string = xmlStrdup(str);
14574 comp->nb = 0;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014575#endif
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014576 if ((comp->expr != NULL) &&
14577 (comp->nbStep > 2) &&
14578 (comp->last >= 0) &&
Kasimier T. Buchcik7cb3fa92006-06-06 15:27:46 +000014579 (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
14580 {
14581 xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014582 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014583 }
Daniel Veillard4773df22004-01-23 13:15:13 +000014584 return(comp);
14585}
14586
14587/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014588 * xmlXPathCompile:
14589 * @str: the XPath expression
14590 *
14591 * Compile an XPath expression
14592 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000014593 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014594 * the caller has to free the object.
14595 */
14596xmlXPathCompExprPtr
14597xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000014598 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014599}
14600
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014601/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014602 * xmlXPathCompiledEvalInternal:
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014603 * @comp: the compiled XPath expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014604 * @ctxt: the XPath context
14605 * @resObj: the resulting XPath object or NULL
14606 * @toBool: 1 if only a boolean result is requested
Owen Taylor3473f882001-02-23 17:55:21 +000014607 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014608 * Evaluate the Precompiled XPath expression in the given context.
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014609 * The caller has to free @resObj.
Owen Taylor3473f882001-02-23 17:55:21 +000014610 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014611 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000014612 * the caller has to free the object.
14613 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014614static int
14615xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14616 xmlXPathContextPtr ctxt,
14617 xmlXPathObjectPtr *resObj,
14618 int toBool)
14619{
14620 xmlXPathParserContextPtr pctxt;
Daniel Veillard81463942001-10-16 12:34:39 +000014621#ifndef LIBXML_THREAD_ENABLED
14622 static int reentance = 0;
14623#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014624 int res;
Owen Taylor3473f882001-02-23 17:55:21 +000014625
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014626 CHECK_CTXT_NEG(ctxt)
William M. Brackf13f77f2004-11-12 16:03:48 +000014627
14628 if (comp == NULL)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014629 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +000014630 xmlXPathInit();
14631
Daniel Veillard81463942001-10-16 12:34:39 +000014632#ifndef LIBXML_THREAD_ENABLED
14633 reentance++;
14634 if (reentance > 1)
14635 xmlXPathDisableOptimizer = 1;
14636#endif
14637
Daniel Veillardf06307e2001-07-03 10:35:50 +000014638#ifdef DEBUG_EVAL_COUNTS
14639 comp->nb++;
14640 if ((comp->string != NULL) && (comp->nb > 100)) {
14641 fprintf(stderr, "100 x %s\n", comp->string);
14642 comp->nb = 0;
14643 }
14644#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014645 pctxt = xmlXPathCompParserContext(comp, ctxt);
14646 res = xmlXPathRunEval(pctxt, toBool);
Owen Taylor3473f882001-02-23 17:55:21 +000014647
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014648 if (resObj) {
14649 if (pctxt->value == NULL) {
14650 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014651 "xmlXPathCompiledEval: evaluation failed\n");
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014652 *resObj = NULL;
14653 } else {
14654 *resObj = valuePop(pctxt);
14655 }
Owen Taylor3473f882001-02-23 17:55:21 +000014656 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014657
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014658 /*
14659 * Pop all remaining objects from the stack.
14660 */
14661 if (pctxt->valueNr > 0) {
14662 xmlXPathObjectPtr tmp;
14663 int stack = 0;
14664
14665 do {
14666 tmp = valuePop(pctxt);
14667 if (tmp != NULL) {
14668 if (tmp != NULL)
14669 stack++;
14670 xmlXPathReleaseObject(ctxt, tmp);
14671 }
14672 } while (tmp != NULL);
14673 if ((stack != 0) &&
14674 ((toBool) || ((resObj) && (*resObj))))
14675 {
14676 xmlGenericError(xmlGenericErrorContext,
14677 "xmlXPathCompiledEval: %d objects left on the stack.\n",
14678 stack);
14679 }
Owen Taylor3473f882001-02-23 17:55:21 +000014680 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014681
14682 if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14683 xmlXPathFreeObject(*resObj);
14684 *resObj = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014685 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014686 pctxt->comp = NULL;
14687 xmlXPathFreeParserContext(pctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000014688#ifndef LIBXML_THREAD_ENABLED
14689 reentance--;
14690#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014691
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014692 return(res);
14693}
14694
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014695/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014696 * xmlXPathCompiledEval:
14697 * @comp: the compiled XPath expression
14698 * @ctx: the XPath context
14699 *
14700 * Evaluate the Precompiled XPath expression in the given context.
14701 *
14702 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14703 * the caller has to free the object.
14704 */
14705xmlXPathObjectPtr
14706xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14707{
14708 xmlXPathObjectPtr res = NULL;
14709
14710 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14711 return(res);
14712}
14713
14714/**
14715 * xmlXPathCompiledEvalToBoolean:
14716 * @comp: the compiled XPath expression
14717 * @ctxt: the XPath context
14718 *
14719 * Applies the XPath boolean() function on the result of the given
14720 * compiled expression.
14721 *
14722 * Returns 1 if the expression evaluated to true, 0 if to false and
14723 * -1 in API and internal errors.
14724 */
14725int
14726xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14727 xmlXPathContextPtr ctxt)
14728{
14729 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14730}
14731
14732/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014733 * xmlXPathEvalExpr:
14734 * @ctxt: the XPath Parser context
14735 *
14736 * Parse and evaluate an XPath expression in the given context,
14737 * then push the result on the context stack
14738 */
14739void
14740xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014741#ifdef XPATH_STREAMING
14742 xmlXPathCompExprPtr comp;
14743#endif
14744
Daniel Veillarda82b1822004-11-08 16:24:57 +000014745 if (ctxt == NULL) return;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014746
14747#ifdef XPATH_STREAMING
14748 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14749 if (comp != NULL) {
14750 if (ctxt->comp != NULL)
14751 xmlXPathFreeCompExpr(ctxt->comp);
14752 ctxt->comp = comp;
14753 if (ctxt->cur != NULL)
14754 while (*ctxt->cur != 0) ctxt->cur++;
14755 } else
14756#endif
14757 {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014758 xmlXPathCompileExpr(ctxt, 1);
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014759 /*
14760 * In this scenario the expression string will sit in ctxt->base.
14761 */
14762 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
14763 (ctxt->comp != NULL) &&
14764 (ctxt->base != NULL) &&
Kasimier T. Buchcik7cb3fa92006-06-06 15:27:46 +000014765 (ctxt->comp->nbStep > 2) &&
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014766 (ctxt->comp->last >= 0) &&
14767 (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014768 {
14769 xmlXPathRewriteDOSExpression(ctxt->comp,
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014770 &ctxt->comp->steps[ctxt->comp->last]);
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014771 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014772 }
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000014773 CHECK_ERROR;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014774 xmlXPathRunEval(ctxt, 0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014775}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014776
14777/**
14778 * xmlXPathEval:
14779 * @str: the XPath expression
14780 * @ctx: the XPath context
14781 *
14782 * Evaluate the XPath Location Path in the given context.
14783 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014784 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014785 * the caller has to free the object.
14786 */
14787xmlXPathObjectPtr
14788xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14789 xmlXPathParserContextPtr ctxt;
14790 xmlXPathObjectPtr res, tmp, init = NULL;
14791 int stack = 0;
14792
William M. Brackf13f77f2004-11-12 16:03:48 +000014793 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014794
William M. Brackf13f77f2004-11-12 16:03:48 +000014795 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014796
14797 ctxt = xmlXPathNewParserContext(str, ctx);
14798 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014799
14800 if (ctxt->value == NULL) {
14801 xmlGenericError(xmlGenericErrorContext,
14802 "xmlXPathEval: evaluation failed\n");
14803 res = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014804 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
14805#ifdef XPATH_STREAMING
14806 && (ctxt->comp->stream == NULL)
14807#endif
14808 ) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014809 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14810 res = NULL;
14811 } else {
14812 res = valuePop(ctxt);
14813 }
14814
14815 do {
14816 tmp = valuePop(ctxt);
14817 if (tmp != NULL) {
14818 if (tmp != init)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014819 stack++;
14820 xmlXPathReleaseObject(ctx, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014821 }
14822 } while (tmp != NULL);
14823 if ((stack != 0) && (res != NULL)) {
14824 xmlGenericError(xmlGenericErrorContext,
14825 "xmlXPathEval: %d object left on the stack\n",
14826 stack);
14827 }
14828 if (ctxt->error != XPATH_EXPRESSION_OK) {
14829 xmlXPathFreeObject(res);
14830 res = NULL;
14831 }
14832
Owen Taylor3473f882001-02-23 17:55:21 +000014833 xmlXPathFreeParserContext(ctxt);
14834 return(res);
14835}
14836
14837/**
14838 * xmlXPathEvalExpression:
14839 * @str: the XPath expression
14840 * @ctxt: the XPath context
14841 *
14842 * Evaluate the XPath expression in the given context.
14843 *
14844 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14845 * the caller has to free the object.
14846 */
14847xmlXPathObjectPtr
14848xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14849 xmlXPathParserContextPtr pctxt;
14850 xmlXPathObjectPtr res, tmp;
14851 int stack = 0;
14852
William M. Brackf13f77f2004-11-12 16:03:48 +000014853 CHECK_CTXT(ctxt)
Owen Taylor3473f882001-02-23 17:55:21 +000014854
William M. Brackf13f77f2004-11-12 16:03:48 +000014855 xmlXPathInit();
Owen Taylor3473f882001-02-23 17:55:21 +000014856
14857 pctxt = xmlXPathNewParserContext(str, ctxt);
14858 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000014859
14860 if (*pctxt->cur != 0) {
14861 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14862 res = NULL;
14863 } else {
14864 res = valuePop(pctxt);
14865 }
14866 do {
14867 tmp = valuePop(pctxt);
14868 if (tmp != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014869 xmlXPathReleaseObject(ctxt, tmp);
Owen Taylor3473f882001-02-23 17:55:21 +000014870 stack++;
14871 }
14872 } while (tmp != NULL);
14873 if ((stack != 0) && (res != NULL)) {
14874 xmlGenericError(xmlGenericErrorContext,
14875 "xmlXPathEvalExpression: %d object left on the stack\n",
14876 stack);
14877 }
14878 xmlXPathFreeParserContext(pctxt);
14879 return(res);
14880}
14881
Daniel Veillard42766c02002-08-22 20:52:17 +000014882/************************************************************************
14883 * *
14884 * Extra functions not pertaining to the XPath spec *
14885 * *
14886 ************************************************************************/
14887/**
14888 * xmlXPathEscapeUriFunction:
14889 * @ctxt: the XPath Parser context
14890 * @nargs: the number of arguments
14891 *
14892 * Implement the escape-uri() XPath function
14893 * string escape-uri(string $str, bool $escape-reserved)
14894 *
14895 * This function applies the URI escaping rules defined in section 2 of [RFC
14896 * 2396] to the string supplied as $uri-part, which typically represents all
14897 * or part of a URI. The effect of the function is to replace any special
14898 * character in the string by an escape sequence of the form %xx%yy...,
14899 * where xxyy... is the hexadecimal representation of the octets used to
14900 * represent the character in UTF-8.
14901 *
14902 * The set of characters that are escaped depends on the setting of the
14903 * boolean argument $escape-reserved.
14904 *
14905 * If $escape-reserved is true, all characters are escaped other than lower
14906 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14907 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14908 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14909 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14910 * A-F).
14911 *
14912 * If $escape-reserved is false, the behavior differs in that characters
14913 * referred to in [RFC 2396] as reserved characters are not escaped. These
14914 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14915 *
14916 * [RFC 2396] does not define whether escaped URIs should use lower case or
14917 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14918 * compared using string comparison functions, this function must always use
14919 * the upper-case letters A-F.
14920 *
14921 * Generally, $escape-reserved should be set to true when escaping a string
14922 * that is to form a single part of a URI, and to false when escaping an
14923 * entire URI or URI reference.
14924 *
14925 * In the case of non-ascii characters, the string is encoded according to
14926 * utf-8 and then converted according to RFC 2396.
14927 *
14928 * Examples
14929 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14930 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14931 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14932 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14933 *
14934 */
Daniel Veillard118aed72002-09-24 14:13:13 +000014935static void
Daniel Veillard42766c02002-08-22 20:52:17 +000014936xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14937 xmlXPathObjectPtr str;
14938 int escape_reserved;
14939 xmlBufferPtr target;
14940 xmlChar *cptr;
14941 xmlChar escape[4];
14942
14943 CHECK_ARITY(2);
14944
14945 escape_reserved = xmlXPathPopBoolean(ctxt);
14946
14947 CAST_TO_STRING;
14948 str = valuePop(ctxt);
14949
14950 target = xmlBufferCreate();
14951
14952 escape[0] = '%';
14953 escape[3] = 0;
14954
14955 if (target) {
14956 for (cptr = str->stringval; *cptr; cptr++) {
14957 if ((*cptr >= 'A' && *cptr <= 'Z') ||
14958 (*cptr >= 'a' && *cptr <= 'z') ||
14959 (*cptr >= '0' && *cptr <= '9') ||
14960 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
14961 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
14962 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14963 (*cptr == '%' &&
14964 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14965 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14966 (cptr[1] >= '0' && cptr[1] <= '9')) &&
14967 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14968 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14969 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14970 (!escape_reserved &&
14971 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14972 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14973 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14974 *cptr == ','))) {
14975 xmlBufferAdd(target, cptr, 1);
14976 } else {
14977 if ((*cptr >> 4) < 10)
14978 escape[1] = '0' + (*cptr >> 4);
14979 else
14980 escape[1] = 'A' - 10 + (*cptr >> 4);
14981 if ((*cptr & 0xF) < 10)
14982 escape[2] = '0' + (*cptr & 0xF);
14983 else
14984 escape[2] = 'A' - 10 + (*cptr & 0xF);
14985
14986 xmlBufferAdd(target, &escape[0], 3);
14987 }
14988 }
14989 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014990 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
14991 xmlBufferContent(target)));
Daniel Veillard42766c02002-08-22 20:52:17 +000014992 xmlBufferFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014993 xmlXPathReleaseObject(ctxt->context, str);
Daniel Veillard42766c02002-08-22 20:52:17 +000014994}
14995
Owen Taylor3473f882001-02-23 17:55:21 +000014996/**
14997 * xmlXPathRegisterAllFunctions:
14998 * @ctxt: the XPath context
14999 *
15000 * Registers all default XPath functions in this context
15001 */
15002void
15003xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15004{
15005 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15006 xmlXPathBooleanFunction);
15007 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15008 xmlXPathCeilingFunction);
15009 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15010 xmlXPathCountFunction);
15011 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15012 xmlXPathConcatFunction);
15013 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15014 xmlXPathContainsFunction);
15015 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15016 xmlXPathIdFunction);
15017 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15018 xmlXPathFalseFunction);
15019 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15020 xmlXPathFloorFunction);
15021 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15022 xmlXPathLastFunction);
15023 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15024 xmlXPathLangFunction);
15025 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15026 xmlXPathLocalNameFunction);
15027 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15028 xmlXPathNotFunction);
15029 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15030 xmlXPathNameFunction);
15031 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15032 xmlXPathNamespaceURIFunction);
15033 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15034 xmlXPathNormalizeFunction);
15035 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15036 xmlXPathNumberFunction);
15037 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15038 xmlXPathPositionFunction);
15039 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15040 xmlXPathRoundFunction);
15041 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15042 xmlXPathStringFunction);
15043 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15044 xmlXPathStringLengthFunction);
15045 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15046 xmlXPathStartsWithFunction);
15047 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15048 xmlXPathSubstringFunction);
15049 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15050 xmlXPathSubstringBeforeFunction);
15051 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15052 xmlXPathSubstringAfterFunction);
15053 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15054 xmlXPathSumFunction);
15055 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15056 xmlXPathTrueFunction);
15057 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15058 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000015059
15060 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15061 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15062 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000015063}
15064
15065#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000015066#define bottom_xpath
15067#include "elfgcchack.h"